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.

949 lines
27 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Generic in-game abuse reporting
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "abuse_report_ui.h"
  9. #include "econ/econ_controls.h"
  10. #include "ienginevgui.h"
  11. #include "vgui/ISurface.h"
  12. #include <vgui_controls/TextEntry.h>
  13. #include <vgui_controls/ComboBox.h>
  14. #include <vgui_controls/RadioButton.h>
  15. #include "vgui_bitmappanel.h"
  16. #include "vgui_avatarimage.h"
  17. #include "gc_clientsystem.h"
  18. #include "econ/tool_items/tool_items.h"
  19. #include "econ/econ_gcmessages.h"
  20. #include "econ/confirm_dialog.h"
  21. #include "tool_items/custom_texture_cache.h"
  22. vgui::DHANDLE<CAbuseReportDlg> g_AbuseReportDlg;
  23. CAbuseReportDlg::CAbuseReportDlg( vgui::Panel *parent, AbuseIncidentData_t *pIncidentData )
  24. : EditablePanel( parent, "AbuseReportSubmitDialog" )
  25. , m_pSubmitButton( NULL )
  26. , m_pScreenShot( NULL )
  27. , m_pScreenShotAttachCheckButton( NULL )
  28. , m_pOffensiveImage( NULL )
  29. , m_pDescriptionTextEntry( NULL )
  30. , m_pPlayerLabel( NULL )
  31. , m_pPlayerRadio( NULL )
  32. , m_pGameServerRadio( NULL )
  33. , m_pPlayerCombo( NULL )
  34. , m_pAbuseContentLabel( NULL )
  35. , m_pAbuseContentCombo( NULL )
  36. , m_pAbuseTypeLabel( NULL )
  37. , m_pAbuseTypeCombo( NULL )
  38. , m_pScreenShotBitmap( NULL )
  39. , m_pAvatarImage( NULL )
  40. , m_pNoAvatarLabel( NULL )
  41. , m_pCustomTextureImagePanel( NULL )
  42. , m_pNoCustomTexturesLabel( NULL )
  43. , m_pCustomTextureNextButton( NULL )
  44. , m_pCustomTexturePrevButton( NULL )
  45. , m_iUserImageIndex( 0 )
  46. , m_pIncidentData( pIncidentData )
  47. {
  48. vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme" );
  49. SetScheme(scheme);
  50. SetProportional( true );
  51. //m_pContainer = new vgui::EditablePanel( this, "Container" );
  52. Assert( g_AbuseReportDlg.Get() == NULL );
  53. g_AbuseReportDlg.Set( this );
  54. engine->ExecuteClientCmd("gameui_preventescape");
  55. }
  56. CAbuseReportDlg::~CAbuseReportDlg()
  57. {
  58. Assert( g_AbuseReportDlg.Get() == this );
  59. if ( g_AbuseReportDlg.Get() == this )
  60. {
  61. engine->ExecuteClientCmd("gameui_allowescape");
  62. g_AbuseReportDlg = NULL;
  63. }
  64. }
  65. void CAbuseReportDlg::OnCommand( const char *command )
  66. {
  67. if ( !Q_stricmp( command, "cancel" ) )
  68. {
  69. Close();
  70. return;
  71. }
  72. if ( !Q_stricmp( command, "discard" ) )
  73. {
  74. Close();
  75. g_AbuseReportMgr->DestroyIncidentData();
  76. return;
  77. }
  78. if ( !Q_stricmp( command, "submit" ) )
  79. {
  80. OnSubmitReport();
  81. return;
  82. }
  83. if ( !Q_stricmp( command, "nextcustomtexture" ) )
  84. {
  85. ++m_iUserImageIndex;
  86. UpdateCustomTextures();
  87. return;
  88. }
  89. if ( !Q_stricmp( command, "prevcustomtexture" ) )
  90. {
  91. --m_iUserImageIndex;
  92. UpdateCustomTextures();
  93. return;
  94. }
  95. }
  96. void CAbuseReportDlg::MakeModal()
  97. {
  98. TFModalStack()->PushModal( this );
  99. MakePopup();
  100. MoveToFront();
  101. SetKeyBoardInputEnabled( true );
  102. SetMouseInputEnabled( true );
  103. // !KLUDGE! Initially set the dialog to be hidden, so we can take a screenshot!
  104. SetEnabled( m_pIncidentData != NULL );
  105. //SetVisible( m_pIncidentData != NULL );
  106. }
  107. void CAbuseReportDlg::Close()
  108. {
  109. TFModalStack()->PopModal( this );
  110. SetVisible( false );
  111. MarkForDeletion();
  112. }
  113. const char *CAbuseReportDlg::GetResFilename()
  114. {
  115. return "Resource/UI/AbuseReportSubmitDialog.res";
  116. //return "Resource/UI/QuickplayDialog.res";
  117. }
  118. void CAbuseReportDlg::PerformLayout()
  119. {
  120. BaseClass::PerformLayout();
  121. // Center it, keeping requested size
  122. int x, y, ww, wt, wide, tall;
  123. vgui::surface()->GetWorkspaceBounds( x, y, ww, wt );
  124. GetSize(wide, tall);
  125. SetPos(x + ((ww - wide) / 2), y + ((wt - tall) / 2));
  126. // @todo setup
  127. }
  128. class CCustomTextureImagePanel : public vgui::Panel
  129. {
  130. public:
  131. CCustomTextureImagePanel( Panel *parent, const char *panelName ) : vgui::Panel( parent, panelName )
  132. {
  133. m_ugcHandle = 0;
  134. }
  135. uint64 m_ugcHandle;
  136. virtual void Paint()
  137. {
  138. if ( m_ugcHandle == 0 )
  139. {
  140. return;
  141. }
  142. int iTextureHandle = GetCustomTextureGuiHandle( m_ugcHandle );
  143. if ( iTextureHandle <= 0)
  144. {
  145. return;
  146. }
  147. vgui::surface()->DrawSetColor(COLOR_WHITE);
  148. vgui::surface()->DrawSetTexture( iTextureHandle );
  149. int iWide, iTall;
  150. GetSize( iWide, iTall );
  151. vgui::Vertex_t verts[4];
  152. verts[0].Init( Vector2D( 0, 0 ), Vector2D( 0.0f, 0.0f ) );
  153. verts[1].Init( Vector2D( iWide, 0 ), Vector2D( 1.0f, 0.0f ) );
  154. verts[2].Init( Vector2D( iWide, iTall ), Vector2D( 1.0f, 1.0f ) );
  155. verts[3].Init( Vector2D( 0, iTall ), Vector2D( 0.0f, 1.0f ) );
  156. vgui::surface()->DrawTexturedPolygon( 4, verts );
  157. vgui::surface()->DrawSetColor(COLOR_WHITE);
  158. }
  159. };
  160. class CAbuseReportScreenShotPanel : public CBitmapPanel
  161. {
  162. public:
  163. CAbuseReportScreenShotPanel( CAbuseReportDlg *pDlg, const char *panelName )
  164. : CBitmapPanel( pDlg, panelName )
  165. , m_pDlg( pDlg )
  166. {}
  167. CAbuseReportDlg *m_pDlg;
  168. virtual void Paint()
  169. {
  170. CBitmapPanel::Paint();
  171. const AbuseIncidentData_t::PlayerData_t *p = m_pDlg->GetAccusedPlayerPtr();
  172. if ( p == NULL || !p->m_bRenderBoundsValid )
  173. {
  174. return;
  175. }
  176. int w, t;
  177. GetSize( w, t );
  178. int x0 = int( p->m_screenBoundsMin.x * (float)w );
  179. int y0 = int( p->m_screenBoundsMin.y * (float)t );
  180. int x1 = int( p->m_screenBoundsMax.x * (float)w );
  181. int y1 = int( p->m_screenBoundsMax.y * (float)t );
  182. vgui::surface()->DrawSetColor( Color(200, 10, 10, 200 ) );
  183. vgui::surface()->DrawOutlinedRect( x0, y0, x1, y1 );
  184. vgui::surface()->DrawSetColor( COLOR_WHITE );
  185. }
  186. };
  187. void CAbuseReportDlg::ApplySchemeSettings( vgui::IScheme *pScheme )
  188. {
  189. EditablePanel::ApplySchemeSettings( pScheme );
  190. m_pScreenShotBitmap = new CAbuseReportScreenShotPanel( this, "ScreenShotBitmap" );
  191. m_pCustomTextureImagePanel = new CCustomTextureImagePanel( this, "CustomTextureImage" );
  192. LoadControlSettings( GetResFilename() );
  193. m_pPlayerRadio = dynamic_cast<vgui::RadioButton *>(FindChildByName( "PlayerRadio", true ));
  194. Assert( m_pPlayerRadio );
  195. if ( m_pPlayerRadio )
  196. {
  197. m_pPlayerRadio->SetVisible( m_pIncidentData->m_bCanReportGameServer );
  198. }
  199. m_pGameServerRadio = dynamic_cast<vgui::RadioButton *>(FindChildByName( "GameServerRadio", true ));
  200. Assert( m_pGameServerRadio );
  201. if ( m_pGameServerRadio )
  202. {
  203. m_pGameServerRadio->SetVisible( m_pIncidentData->m_bCanReportGameServer );
  204. }
  205. m_pPlayerLabel = FindChildByName( "PlayerLabel", true );
  206. Assert( m_pPlayerLabel );
  207. m_pScreenShotAttachCheckButton = dynamic_cast<vgui::CheckButton *>(FindChildByName( "ScreenShotAttachCheckButton", true ));
  208. Assert( m_pScreenShotAttachCheckButton );
  209. if ( m_pScreenShotAttachCheckButton )
  210. {
  211. m_pScreenShotAttachCheckButton->SetSelected( true );
  212. }
  213. m_pSubmitButton = dynamic_cast<vgui::Button *>(FindChildByName( "SubmitButton", true ));
  214. Assert( m_pSubmitButton );
  215. m_pDescriptionTextEntry = dynamic_cast<vgui::TextEntry *>(FindChildByName( "DescriptionTextEntry", true ));
  216. Assert( m_pDescriptionTextEntry );
  217. if ( m_pDescriptionTextEntry )
  218. {
  219. m_pDescriptionTextEntry->SetMultiline( true );
  220. }
  221. m_pAvatarImage = dynamic_cast<CAvatarImagePanel *>(FindChildByName( "AvatarImage", true ));
  222. Assert( m_pAvatarImage );
  223. m_pNoAvatarLabel = FindChildByName( "NoAvatarLabel", true );
  224. Assert( m_pNoAvatarLabel );
  225. m_pNoCustomTexturesLabel = FindChildByName( "NoCustomTexturesLabel", true );
  226. Assert( m_pNoCustomTexturesLabel );
  227. m_pCustomTextureNextButton = dynamic_cast<vgui::Button *>(FindChildByName( "CustomTextureNextButton", true ));
  228. Assert( m_pCustomTextureNextButton );
  229. m_pCustomTexturePrevButton = dynamic_cast<vgui::Button *>(FindChildByName( "CustomTexturePrevButton", true ));
  230. Assert( m_pCustomTexturePrevButton );
  231. m_pPlayerCombo = dynamic_cast<vgui::ComboBox *>(FindChildByName( "PlayerComboBox", true ));
  232. Assert( m_pPlayerCombo );
  233. m_pAbuseContentLabel = FindChildByName( "AbuseContentLabel", true );
  234. Assert( m_pAbuseContentLabel );
  235. m_pAbuseContentCombo = dynamic_cast<vgui::ComboBox *>(FindChildByName( "AbuseContentComboBox", true ));
  236. Assert( m_pAbuseContentCombo );
  237. if ( m_pAbuseContentCombo )
  238. {
  239. m_pAbuseContentCombo->AddItem( "#AbuseReport_SelectOne", new KeyValues( "AbuseContent", "code", k_EAbuseReportContentNoSelection ) );
  240. m_pAbuseContentCombo->AddItem( "#AbuseReport_ContentAvatarImage", new KeyValues( "AbuseContent", "code", k_EAbuseReportContentAvatarImage ) );
  241. m_pAbuseContentCombo->AddItem( "#AbuseReport_ContentPlayerName", new KeyValues( "AbuseContent", "code", k_EAbuseReportContentPersonaName ) );
  242. m_pAbuseContentCombo->AddItem( "#AbuseReport_ContentItemDecal", new KeyValues( "AbuseContent", "code", k_EAbuseReportContentUGCImage ) );
  243. m_pAbuseContentCombo->AddItem( "#AbuseReport_ContentChatText", new KeyValues( "AbuseContent", "code", k_EAbuseReportContentComments ) );
  244. m_pAbuseContentCombo->AddItem( "#AbuseReport_ContentCheating", new KeyValues( "AbuseContent", "code", k_EAbuseReportContentCheating ) );
  245. m_pAbuseContentCombo->AddItem( "#AbuseReport_ContentOther", new KeyValues( "AbuseContent", "code", k_EAbuseReportContentUnspecified ) );
  246. m_pAbuseContentCombo->SilentActivateItemByRow( 0 );
  247. m_pAbuseContentCombo->SetNumberOfEditLines( m_pAbuseContentCombo->GetItemCount() );
  248. }
  249. m_pAbuseTypeLabel = FindChildByName( "AbuseTypeLabel", true );
  250. Assert( m_pAbuseTypeLabel );
  251. m_pAbuseTypeCombo = dynamic_cast<vgui::ComboBox *>(FindChildByName( "AbuseTypeComboBox", true ));
  252. Assert( m_pAbuseTypeCombo );
  253. Assert( m_pScreenShotBitmap );
  254. if ( m_pScreenShotBitmap && m_pIncidentData->m_bitmapScreenshot.IsValid() )
  255. {
  256. m_pScreenShotBitmap->SetBitmap( m_pIncidentData->m_bitmapScreenshot );
  257. }
  258. PopulatePlayerList();
  259. SetIsAccusingGameServer( false );
  260. SetEnabled( true );
  261. SetVisible( true );
  262. }
  263. bool CAbuseReportDlg::IsAccusingGameServer()
  264. {
  265. return m_pIncidentData && m_pIncidentData->m_bCanReportGameServer && m_pGameServerRadio && m_pGameServerRadio->IsSelected();
  266. }
  267. EAbuseReportContentType CAbuseReportDlg::GetAbuseContentType()
  268. {
  269. if ( m_pAbuseContentCombo == NULL || IsAccusingGameServer() )
  270. {
  271. Assert( m_pAbuseContentCombo );
  272. return k_EAbuseReportContentNoSelection;
  273. }
  274. KeyValues *pUserData = m_pAbuseContentCombo->GetActiveItemUserData();
  275. if ( pUserData == NULL )
  276. {
  277. return k_EAbuseReportContentNoSelection;
  278. }
  279. return (EAbuseReportContentType)pUserData->GetInt( "code", k_EAbuseReportContentNoSelection );
  280. }
  281. EAbuseReportType CAbuseReportDlg::GetAbuseType()
  282. {
  283. if ( m_pAbuseTypeCombo == NULL || IsAccusingGameServer() )
  284. {
  285. Assert( m_pAbuseTypeCombo );
  286. return k_EAbuseReportTypeNoSelection;
  287. }
  288. KeyValues *pUserData = m_pAbuseTypeCombo->GetActiveItemUserData();
  289. if ( pUserData == NULL )
  290. {
  291. return k_EAbuseReportTypeNoSelection;
  292. }
  293. return (EAbuseReportType)pUserData->GetInt( "code", k_EAbuseReportTypeNoSelection );
  294. }
  295. CUtlString CAbuseReportDlg::GetAbuseDescription()
  296. {
  297. char buf[ 1024 ] = "";
  298. if ( m_pDescriptionTextEntry )
  299. {
  300. m_pDescriptionTextEntry->GetText( buf, ARRAYSIZE(buf) );
  301. }
  302. return CUtlString( buf );
  303. }
  304. int CAbuseReportDlg::GetAccusedPlayerIndex()
  305. {
  306. // If accusing a game server, then there's no player
  307. if ( IsAccusingGameServer() )
  308. {
  309. return -1;
  310. }
  311. if ( m_pPlayerCombo == NULL )
  312. {
  313. Assert( m_pPlayerCombo );
  314. return -1;
  315. }
  316. // Item 0 is the "<select one>" item
  317. return m_pPlayerCombo->GetActiveItem() - 1;
  318. }
  319. const AbuseIncidentData_t::PlayerData_t *CAbuseReportDlg::GetAccusedPlayerPtr()
  320. {
  321. int iPlayerIndex = GetAccusedPlayerIndex();
  322. if ( iPlayerIndex < 0 )
  323. return NULL;
  324. return &m_pIncidentData->m_vecPlayers[ iPlayerIndex ];
  325. }
  326. bool CAbuseReportDlg::GetAttachScreenShot()
  327. {
  328. if ( m_pScreenShotAttachCheckButton == NULL )
  329. {
  330. return false;
  331. }
  332. if ( !m_pScreenShotAttachCheckButton->IsVisible() )
  333. {
  334. // We hide the checkbutton when the option is not applicable
  335. return false;
  336. }
  337. return m_pScreenShotAttachCheckButton->IsSelected();
  338. }
  339. void CAbuseReportDlg::PopulatePlayerList()
  340. {
  341. if ( m_pIncidentData == NULL || m_pPlayerCombo == NULL )
  342. {
  343. Assert( m_pIncidentData );
  344. Assert( m_pPlayerCombo );
  345. return;
  346. }
  347. m_pPlayerCombo->RemoveAll();
  348. m_pPlayerCombo->AddItem( "#AbuseReport_SelectOne", NULL );
  349. for ( int i = 0 ; i < m_pIncidentData->m_vecPlayers.Count() ; ++i )
  350. {
  351. AbuseIncidentData_t::PlayerData_t *p = &m_pIncidentData->m_vecPlayers[i];
  352. m_pPlayerCombo->AddItem( p->m_sPersona, NULL );
  353. }
  354. m_pPlayerCombo->SilentActivateItemByRow( 0 );
  355. m_pPlayerCombo->SetNumberOfEditLines( MIN( m_pPlayerCombo->GetItemCount()+1, 12 ) );
  356. }
  357. void CAbuseReportDlg::UpdateSubmitButton()
  358. {
  359. if ( !m_pSubmitButton )
  360. {
  361. Assert( m_pSubmitButton );
  362. return;
  363. }
  364. bool bEnable = false;
  365. if ( IsAccusingGameServer() )
  366. {
  367. bEnable = true;
  368. }
  369. else
  370. {
  371. EAbuseReportContentType eContent = GetAbuseContentType();
  372. const AbuseIncidentData_t::PlayerData_t *pAccused = GetAccusedPlayerPtr();
  373. if (
  374. eContent >= 0
  375. && GetAbuseType() >= 0
  376. && pAccused != NULL )
  377. {
  378. bEnable = true;
  379. if ( eContent == k_EAbuseReportContentAvatarImage && pAccused->m_iSteamAvatarIndex <= 0 )
  380. {
  381. // Cannot accuse somebody of having a bad avatar image, if they
  382. // don't have one set
  383. bEnable = false;
  384. }
  385. }
  386. }
  387. if ( GetAbuseDescription().IsEmpty() )
  388. {
  389. bEnable = false;
  390. }
  391. m_pSubmitButton->SetEnabled( bEnable );
  392. }
  393. void CAbuseReportDlg::ContentTypeChanged()
  394. {
  395. // Save current abuse type. We want to keep it the same,
  396. // if possible
  397. EAbuseReportType abuseType = GetAbuseType();
  398. EAbuseReportContentType contentType = GetAbuseContentType();
  399. // Show/hide screen shot / image select
  400. bool bShowScreenshot = false;
  401. bool bShowAttach = false;
  402. switch ( contentType )
  403. {
  404. default:
  405. Assert( false );
  406. case k_EAbuseReportContentNoSelection:
  407. case k_EAbuseReportContentPersonaName:
  408. bShowScreenshot = true;
  409. bShowAttach = false;
  410. break;
  411. case k_EAbuseReportContentUnspecified:
  412. case k_EAbuseReportContentComments:
  413. case k_EAbuseReportContentCheating:
  414. bShowScreenshot = true;
  415. bShowAttach = true;
  416. break;
  417. case k_EAbuseReportContentAvatarImage:
  418. case k_EAbuseReportContentUGCImage:
  419. bShowScreenshot = false;
  420. bShowAttach = false;
  421. break;
  422. }
  423. bShowScreenshot = bShowScreenshot && m_pIncidentData->m_bitmapScreenshot.IsValid();
  424. // Make sure we have everything we need to upload a screenshot
  425. bShowAttach = bShowAttach
  426. && bShowScreenshot
  427. && ( GetAccusedPlayerIndex() >= 0 )
  428. && m_pIncidentData->m_bufScreenshotFileData.TellPut() > 0
  429. && steamapicontext
  430. && ( steamapicontext->SteamUtils() != NULL )
  431. && ( steamapicontext->SteamRemoteStorage() != NULL );
  432. if ( m_pScreenShotBitmap )
  433. {
  434. m_pScreenShotBitmap->SetVisible( bShowScreenshot );
  435. }
  436. if ( m_pScreenShotAttachCheckButton )
  437. {
  438. m_pScreenShotAttachCheckButton->SetVisible( bShowAttach );
  439. }
  440. UpdateAvatarImage();
  441. UpdateCustomTextures();
  442. // Populate abuse type
  443. if ( m_pAbuseTypeCombo )
  444. {
  445. // If the combo box was invisible, then they didn't really make a purposeful decision
  446. if ( !m_pAbuseTypeCombo->IsVisible() )
  447. {
  448. abuseType = k_EAbuseReportTypeNoSelection;
  449. }
  450. m_pAbuseTypeCombo->RemoveAll();
  451. switch ( contentType )
  452. {
  453. default:
  454. Assert( false );
  455. case k_EAbuseReportContentNoSelection:
  456. m_pAbuseTypeCombo->SetVisible( false );
  457. abuseType = k_EAbuseReportTypeNoSelection;
  458. m_pAbuseTypeCombo->AddItem( "#AbuseReport_SelectOne", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeNoSelection ) );
  459. break;
  460. case k_EAbuseReportContentCheating:
  461. m_pAbuseTypeCombo->SetVisible( false );
  462. abuseType = k_EAbuseReportTypeCheating;
  463. m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeCheating", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeCheating ) );
  464. break;
  465. case k_EAbuseReportContentUnspecified:
  466. case k_EAbuseReportContentComments:
  467. case k_EAbuseReportContentPersonaName:
  468. case k_EAbuseReportContentAvatarImage:
  469. case k_EAbuseReportContentUGCImage:
  470. m_pAbuseTypeCombo->SetVisible( true );
  471. m_pAbuseTypeCombo->AddItem( "#AbuseReport_SelectOne", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeNoSelection ) );
  472. m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeSpam", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeSpamming ) );
  473. m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeAdvertisement", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeAdvertisement ) );
  474. m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeLanguage", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeLanguage ) );
  475. m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeAdultContent", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeAdultContent ) );
  476. m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeHarassment", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeHarassment ) );
  477. m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeProhibited", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeProhibited ) );
  478. m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeSpoofing", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeSpoofing ) );
  479. //m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeCheating", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeCheating ) );
  480. m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeInappropriate", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeInappropriate ) );
  481. m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeOther", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeUnspecified ) );
  482. break;
  483. }
  484. // Now select the proper row
  485. int sel = 0;
  486. for ( int i = 0 ; i < m_pAbuseTypeCombo->GetItemCount() ; ++i ) {
  487. if ( m_pAbuseTypeCombo->GetItemUserData(i)->GetInt("code") == abuseType )
  488. {
  489. sel = i;
  490. break;
  491. }
  492. }
  493. m_pAbuseTypeCombo->SilentActivateItemByRow( sel );
  494. m_pAbuseTypeCombo->SetNumberOfEditLines( m_pAbuseTypeCombo->GetItemCount() );
  495. if ( m_pAbuseTypeLabel )
  496. {
  497. m_pAbuseTypeLabel->SetVisible( m_pAbuseTypeCombo->IsVisible() );
  498. }
  499. }
  500. UpdateSubmitButton();
  501. }
  502. void CAbuseReportDlg::OnRadioButtonChecked( vgui::Panel *panel )
  503. {
  504. if ( panel == m_pPlayerRadio )
  505. {
  506. SetIsAccusingGameServer( false );
  507. }
  508. else if ( panel == m_pGameServerRadio )
  509. {
  510. SetIsAccusingGameServer( true );
  511. }
  512. else
  513. {
  514. Assert( !"Clicked on unknown radio" );
  515. }
  516. }
  517. void CAbuseReportDlg::SetIsAccusingGameServer( bool bAccuseGameServer )
  518. {
  519. if ( m_pGameServerRadio && m_pGameServerRadio->IsSelected() != bAccuseGameServer )
  520. {
  521. m_pGameServerRadio->SetSelected( bAccuseGameServer );
  522. }
  523. if ( m_pPlayerRadio && m_pPlayerRadio->IsSelected() == bAccuseGameServer)
  524. {
  525. m_pPlayerRadio->SetSelected( !bAccuseGameServer );
  526. }
  527. if ( m_pPlayerLabel )
  528. {
  529. m_pPlayerLabel->SetVisible( !bAccuseGameServer );
  530. }
  531. if ( m_pPlayerCombo )
  532. {
  533. m_pPlayerCombo->SetVisible( !bAccuseGameServer );
  534. }
  535. PlayerChanged();
  536. }
  537. void CAbuseReportDlg::PlayerChanged()
  538. {
  539. m_iUserImageIndex = 0;
  540. bool bShow = ( GetAccusedPlayerIndex() >= 0 );
  541. if ( m_pAbuseContentCombo != NULL )
  542. {
  543. m_pAbuseContentCombo->SetVisible( bShow );
  544. }
  545. if ( m_pAbuseContentLabel != NULL )
  546. {
  547. m_pAbuseContentLabel->SetVisible( bShow );
  548. }
  549. ContentTypeChanged();
  550. }
  551. void CAbuseReportDlg::UpdateAvatarImage()
  552. {
  553. if ( m_pAvatarImage == NULL || m_pNoAvatarLabel == NULL )
  554. {
  555. Assert( m_pAvatarImage );
  556. Assert( m_pNoAvatarLabel );
  557. return;
  558. }
  559. const AbuseIncidentData_t::PlayerData_t *pAccused = GetAccusedPlayerPtr();
  560. if ( GetAbuseContentType() == k_EAbuseReportContentAvatarImage && pAccused != NULL )
  561. {
  562. if ( pAccused->m_iSteamAvatarIndex > 0 )
  563. {
  564. m_pAvatarImage->SetShouldDrawFriendIcon( false );
  565. m_pAvatarImage->SetPlayer( pAccused->m_steamID, k_EAvatarSize184x184 );
  566. m_pAvatarImage->SetVisible( true );
  567. m_pNoAvatarLabel->SetVisible( false );
  568. }
  569. else
  570. {
  571. m_pAvatarImage->SetVisible( false );
  572. m_pNoAvatarLabel->SetVisible( true );
  573. }
  574. }
  575. else
  576. {
  577. m_pAvatarImage->SetVisible( false );
  578. m_pNoAvatarLabel->SetVisible( false );
  579. }
  580. }
  581. void CAbuseReportDlg::UpdateCustomTextures()
  582. {
  583. if ( m_pCustomTextureImagePanel == NULL || m_pNoCustomTexturesLabel == NULL || m_pCustomTextureNextButton == NULL || m_pCustomTexturePrevButton == NULL )
  584. {
  585. Assert( m_pCustomTextureImagePanel );
  586. Assert( m_pNoCustomTexturesLabel );
  587. Assert( m_pCustomTextureNextButton );
  588. Assert( m_pCustomTexturePrevButton );
  589. return;
  590. }
  591. const AbuseIncidentData_t::PlayerData_t *pAccused = GetAccusedPlayerPtr();
  592. bool bShowScrollButtons = false;
  593. if ( GetAbuseContentType() == k_EAbuseReportContentUGCImage && pAccused != NULL )
  594. {
  595. int iSelectedCustomImage = GetSelectedCustomImage();
  596. if ( iSelectedCustomImage >= 0 )
  597. {
  598. // Currently the only thing we support...
  599. Assert( pAccused->m_vecImages[ iSelectedCustomImage].m_eType == AbuseIncidentData_t::k_PlayerImageType_UGC );
  600. m_pCustomTextureImagePanel->m_ugcHandle = pAccused->m_vecImages[ iSelectedCustomImage].m_hUGCHandle;
  601. m_pCustomTextureImagePanel->SetVisible( true );
  602. m_pNoCustomTexturesLabel->SetVisible( false );
  603. int n = pAccused->m_vecImages.Count();
  604. if ( n > 1 )
  605. {
  606. bShowScrollButtons = true;
  607. m_pCustomTextureNextButton->SetEnabled( iSelectedCustomImage < n-1 );
  608. m_pCustomTexturePrevButton->SetEnabled( iSelectedCustomImage > 0 );
  609. }
  610. }
  611. else
  612. {
  613. m_pCustomTextureImagePanel->SetVisible( false );
  614. m_pNoCustomTexturesLabel->SetVisible( true );
  615. }
  616. }
  617. else
  618. {
  619. m_pCustomTextureImagePanel->SetVisible( false );
  620. m_pNoCustomTexturesLabel->SetVisible( false );
  621. }
  622. m_pCustomTextureNextButton->SetVisible( bShowScrollButtons );
  623. m_pCustomTexturePrevButton->SetVisible( bShowScrollButtons );
  624. }
  625. int CAbuseReportDlg::GetSelectedCustomImage()
  626. {
  627. if ( GetAbuseContentType() != k_EAbuseReportContentUGCImage )
  628. {
  629. m_iUserImageIndex = 0;
  630. return -1;
  631. }
  632. const AbuseIncidentData_t::PlayerData_t *pAccused = GetAccusedPlayerPtr();
  633. if ( pAccused == NULL )
  634. {
  635. m_iUserImageIndex = 0;
  636. return -1;
  637. }
  638. int n = pAccused->m_vecImages.Count();
  639. if ( n < 1 )
  640. {
  641. m_iUserImageIndex = 0;
  642. return -1;
  643. }
  644. // Wrap currently selected index
  645. m_iUserImageIndex = ( m_iUserImageIndex + n*10 ) % n;
  646. // Return it
  647. return m_iUserImageIndex;
  648. }
  649. void CAbuseReportDlg::OnTextChanged( vgui::Panel *panel )
  650. {
  651. if ( panel == m_pPlayerCombo )
  652. {
  653. PlayerChanged();
  654. }
  655. else if ( panel == m_pAbuseContentCombo )
  656. {
  657. ContentTypeChanged();
  658. }
  659. else
  660. {
  661. UpdateSubmitButton();
  662. }
  663. }
  664. //-----------------------------------------------------------------------------
  665. // Purpose: Job to do the async work of submitting the report
  666. //-----------------------------------------------------------------------------
  667. class CSubmitAbuseReportJob : public GCSDK::CGCClientJob
  668. {
  669. public:
  670. bool m_bGameServer;
  671. CSubmitAbuseReportJob( )
  672. : GCSDK::CGCClientJob( GCClientSystem()->GetGCClient() )
  673. {
  674. m_bGameServer = false;
  675. }
  676. virtual bool BYieldingRunGCJob()
  677. {
  678. EResult result = RunJob();
  679. // Tear down our dialogs
  680. CloseWaitingDialog();
  681. CAbuseReportDlg *pDlg = g_AbuseReportDlg.Get();
  682. if ( pDlg )
  683. {
  684. pDlg->Close();
  685. pDlg = NULL;
  686. }
  687. // And destroy the queued report!
  688. g_AbuseReportMgr->DestroyIncidentData();
  689. // now show a dialog box explaining the outcome
  690. switch ( result )
  691. {
  692. case k_EResultOK:
  693. ShowMessageBox( "#AbuseReport_SucceededTitle", "#AbuseReport_SucceededMessage", "#GameUI_OK" );
  694. break;
  695. case k_EResultLimitExceeded:
  696. ShowMessageBox(
  697. "#AbuseReport_TooMuchFailedTitle",
  698. m_bGameServer ? "#AbuseReport_TooMuchFailedMessageGameServer" : "#AbuseReport_TooMuchFailedMessage",
  699. "#GameUI_OK"
  700. );
  701. break;
  702. default:
  703. ShowMessageBox( "#AbuseReport_GenericFailureTitle", "#AbuseReport_GenericFailureMessage", "#GameUI_OK" );
  704. break;
  705. }
  706. return true;
  707. }
  708. EResult RunJob()
  709. {
  710. CAbuseReportDlg *pDlg = g_AbuseReportDlg.Get();
  711. if ( pDlg == NULL )
  712. {
  713. return k_EResultFail;
  714. }
  715. m_bGameServer = pDlg->IsAccusingGameServer();
  716. EAbuseReportContentType eContentSelected = pDlg->GetAbuseContentType();
  717. EAbuseReportContentType eContentReported = eContentSelected;
  718. EAbuseReportType eAbuseType = pDlg->GetAbuseType();
  719. const AbuseIncidentData_t::PlayerData_t *pAccused = pDlg->GetAccusedPlayerPtr();
  720. const AbuseIncidentData_t *pIncidentData = g_AbuseReportMgr->GetIncidentData();
  721. CUtlString sAbuseDescription = pDlg->GetAbuseDescription();
  722. netadr_t adrGameServer = pIncidentData->m_adrGameServer;
  723. CSteamID steamIDGameServer = pIncidentData->m_steamIDGameServer;
  724. uint64 gid = 0;
  725. // Check if we should upload the screenshot
  726. if ( pDlg->GetAttachScreenShot() && steamapicontext && steamapicontext->SteamUtils() && steamapicontext->SteamRemoteStorage() )
  727. {
  728. // Write the local copy of the file
  729. if ( !steamapicontext->SteamRemoteStorage()->FileWrite( CAbuseReportManager::k_rchScreenShotFilename, pIncidentData->m_bufScreenshotFileData.Base(), pIncidentData->m_bufScreenshotFileData.TellPut() ) )
  730. {
  731. Warning( "Failed to save local cloud copy of %s\n", CAbuseReportManager::k_rchScreenShotFilename );
  732. return k_EResultFail;
  733. }
  734. // Share it. This initiates the upload to cloud
  735. Msg( "Starting upload of %s to UFS....\n", CAbuseReportManager::k_rchScreenShotFilename );
  736. SteamAPICall_t hFileShareApiCall = steamapicontext->SteamRemoteStorage()->FileShare( CAbuseReportManager::k_rchScreenShotFilename );
  737. if ( hFileShareApiCall == k_uAPICallInvalid )
  738. {
  739. Warning( "Failed to share %s\n", CAbuseReportManager::k_rchScreenShotFilename );
  740. return k_EResultFail;
  741. }
  742. // Check if we're busy
  743. bool bFailed;
  744. RemoteStorageFileShareResult_t result;
  745. while ( !steamapicontext->SteamUtils()->GetAPICallResult(hFileShareApiCall,
  746. &result, sizeof(result), RemoteStorageFileShareResult_t::k_iCallback, &bFailed) )
  747. {
  748. BYield();
  749. }
  750. // Clear pointer, it could have been destroyed while we were yielding, make sure we don't reference it
  751. pDlg = NULL;
  752. if ( bFailed || result.m_eResult != k_EResultOK )
  753. {
  754. Warning( "Failed to share %s; result code %d\n", CAbuseReportManager::k_rchScreenShotFilename, result.m_eResult );
  755. return result.m_eResult;
  756. }
  757. Msg( "%s shared to UGC OK\n", CAbuseReportManager::k_rchScreenShotFilename );
  758. gid = result.m_hFile;
  759. // SWitch the content type being reported, so the support tool will know what to
  760. // do with the GID.
  761. eContentReported = k_EAbuseReportContentActorUGCImage;
  762. }
  763. else if ( eContentSelected == k_EAbuseReportContentUGCImage )
  764. {
  765. Assert( !m_bGameServer );
  766. int iImageindex = pDlg->GetSelectedCustomImage();
  767. Assert( iImageindex >= 0 );
  768. gid = pAccused->m_vecImages[iImageindex].m_hUGCHandle;
  769. }
  770. //
  771. // Fill out the report message
  772. //
  773. GCSDK::CProtoBufMsg<CMsgGCReportAbuse> msg( k_EMsgGC_ReportAbuse );
  774. if ( m_bGameServer )
  775. {
  776. msg.Body().set_target_steam_id( steamIDGameServer.ConvertToUint64() );
  777. msg.Body().set_target_game_server_ip( adrGameServer.GetIPHostByteOrder() );
  778. msg.Body().set_target_game_server_port( adrGameServer.GetPort() );
  779. }
  780. else
  781. {
  782. msg.Body().set_target_steam_id( pAccused->m_steamID.ConvertToUint64() );
  783. msg.Body().set_content_type( eContentReported );
  784. msg.Body().set_abuse_type( eAbuseType );
  785. }
  786. msg.Body().set_description( sAbuseDescription );
  787. if (gid != 0 )
  788. {
  789. msg.Body().set_gid( gid );
  790. }
  791. // Send the message to the GC, and await the reply
  792. GCSDK::CProtoBufMsg<CMsgGCReportAbuseResponse> msgReply;
  793. if ( !BYldSendMessageAndGetReply( msg, 10, &msgReply, k_EMsgGC_ReportAbuseResponse ) )
  794. {
  795. Warning( "Abuse report failed: Did not get reply from GC\n" );
  796. return k_EResultTimeout;
  797. }
  798. EResult result = (EResult)msgReply.Body().result();
  799. if ( result != k_EResultOK )
  800. {
  801. Warning( "Abuse report failed with failure code %d. %s\n", result, msgReply.Body().error_message().c_str() );
  802. }
  803. // OK
  804. return result;
  805. }
  806. };
  807. void CAbuseReportDlg::OnSubmitReport()
  808. {
  809. // throw up a waiting dialog
  810. SetEnabled( false );
  811. ShowWaitingDialog( new CGenericWaitingDialog( this ), "#AbuseReport_Busy", true, false, 0.0f );
  812. // We need to be in the global singleton handle, because that's how the job knows
  813. // to get to us (and how it knows if we've died)!
  814. Assert( g_AbuseReportDlg.Get() == this );
  815. // Start a job
  816. CSubmitAbuseReportJob *pJob = new CSubmitAbuseReportJob();
  817. pJob->StartJob( NULL );
  818. }