summaryrefslogtreecommitdiff
path: root/game/client/tf/vgui/tf_matchmaking_dashboard.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/client/tf/vgui/tf_matchmaking_dashboard.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/client/tf/vgui/tf_matchmaking_dashboard.cpp')
-rw-r--r--game/client/tf/vgui/tf_matchmaking_dashboard.cpp594
1 files changed, 594 insertions, 0 deletions
diff --git a/game/client/tf/vgui/tf_matchmaking_dashboard.cpp b/game/client/tf/vgui/tf_matchmaking_dashboard.cpp
new file mode 100644
index 0000000..ca10e8b
--- /dev/null
+++ b/game/client/tf/vgui/tf_matchmaking_dashboard.cpp
@@ -0,0 +1,594 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+
+#include "cbase.h"
+#include "tf_shareddefs.h"
+#include "tf_matchmaking_dashboard.h"
+#include "tf_gamerules.h"
+#include "ienginevgui.h"
+#include "clientmode_tf.h"
+#include "tf_hud_disconnect_prompt.h"
+#include "tf_gc_client.h"
+#include "tf_party.h"
+#include "../vgui2/src/VPanel.h"
+
+using namespace vgui;
+using namespace GCSDK;
+
+ConVar tf_mm_dashboard_spew_enabled( "tf_mm_dashboard_spew_enabled", "0", FCVAR_ARCHIVE );
+#define MMDashboardSpew(...) \
+ do { \
+ if ( tf_mm_dashboard_spew_enabled.GetBool() ) \
+ { \
+ ConColorMsg( Color( 187, 80, 255, 255 ), "MMDashboard:" __VA_ARGS__ ); \
+ } \
+ } while(false) \
+
+extern ConVar tf_mm_next_map_vote_time;
+
+#ifdef STAGING_ONLY
+ConVar tf_mm_dashboard_force_show( "tf_mm_dashboard_force_show", "0", 0, "Force the mm dashboard to show" );
+ConVar tf_mm_popup_state_override( "tf_mm_popup_state_override", "", 0, "Force state on mm dashboard popup" );
+#endif
+
+
+
+bool BInEndOfMatch()
+{
+ const bool bInEndOfMatch = TFGameRules() &&
+ TFGameRules()->State_Get() == GR_STATE_GAME_OVER &&
+ GTFGCClientSystem()->BConnectedToMatchServer( false );
+
+ return bInEndOfMatch;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Pnael that lives on the viewport that is a popup that we parent
+// the MM dashboard panels to
+//-----------------------------------------------------------------------------
+class CMatchMakingHUDPopupContainer : public Panel
+{
+public:
+ DECLARE_CLASS_SIMPLE( CMatchMakingHUDPopupContainer, Panel );
+ CMatchMakingHUDPopupContainer()
+ : Panel( g_pClientMode->GetViewport(), "MMDashboardPopupContainer" )
+ {
+ SetProportional( true );
+ SetBounds( 0, 0, g_pClientMode->GetViewport()->GetWide(), g_pClientMode->GetViewport()->GetTall() );
+ MakePopup();
+ SetMouseInputEnabled( true );
+ SetKeyBoardInputEnabled( false ); // This can never be true
+ SetVisible( false );
+ ivgui()->AddTickSignal( GetVPanel(), 100 );
+ }
+
+ virtual void OnTick()
+ {
+ BaseClass::OnThink();
+
+ bool bChildrenVisible = false;
+ int nCount = GetChildCount();
+ for( int i=0; i < nCount && !bChildrenVisible; ++i )
+ {
+ CExpandablePanel* pChild = assert_cast< CExpandablePanel* >( GetChild( i ) );
+ bChildrenVisible = bChildrenVisible || pChild->BIsExpanded() || ( !pChild->BIsExpanded() && pChild->GetPercentAnimated() != 1.f );
+ }
+
+ SetVisible( bChildrenVisible );
+ }
+};
+
+CMMDashboardParentManager::CMMDashboardParentManager()
+ : m_bAttachedToGameUI( false )
+{
+ ListenForGameEvent( "gameui_activated" );
+ ListenForGameEvent( "gameui_hidden" );
+
+ m_pHUDPopup = new CMatchMakingHUDPopupContainer();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Update who we need to parent the MM dashboard panels to
+//-----------------------------------------------------------------------------
+void CMMDashboardParentManager::FireGameEvent( IGameEvent *event )
+{
+ if ( FStrEq( event->GetName(), "gameui_activated" ) )
+ {
+ m_bAttachedToGameUI = false;
+ }
+ else if ( FStrEq( event->GetName(), "gameui_hidden" ) )
+ {
+ m_bAttachedToGameUI = true;
+ }
+
+ UpdateParenting();
+}
+
+void CMMDashboardParentManager::AddPanel( CExpandablePanel* pPanel )
+{
+ m_vecPanels.Insert( pPanel );
+ UpdateParenting();
+}
+
+void CMMDashboardParentManager::RemovePanel( CExpandablePanel* pPanel )
+{
+ m_vecPanels.FindAndRemove( pPanel );
+ m_vecPanels.RedoSort();
+ UpdateParenting();
+}
+
+void CMMDashboardParentManager::PushModalFullscreenPopup( vgui::Panel* pPanel )
+{
+ m_vecFullscreenPopups.AddToTail( pPanel );
+ UpdateParenting();
+}
+
+void CMMDashboardParentManager::PopModalFullscreenPopup( vgui::Panel* pPanel )
+{
+ m_vecFullscreenPopups.FindAndRemove( pPanel );
+ UpdateParenting();
+}
+
+void CMMDashboardParentManager::UpdateParenting()
+{
+ m_bAttachedToGameUI ? AttachToGameUI() : AttachToTopMostPopup();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Parent the MM dashboard panels to the right panels
+//-----------------------------------------------------------------------------
+void CMMDashboardParentManager::AttachToGameUI()
+{
+ if ( !m_pHUDPopup )
+ {
+ return;
+ }
+
+ FOR_EACH_VEC( m_vecPanels, i )
+ {
+ CExpandablePanel *pPanel = m_vecPanels[ i ];
+ bool bKBInput = pPanel->IsKeyBoardInputEnabled();
+ bool bMouseInput = pPanel->IsMouseInputEnabled();
+
+ pPanel->SetParent( (Panel*)m_pHUDPopup );
+
+ // Restore mouse, KV input sensitivity because MakePopup forces both to true
+ pPanel->SetKeyBoardInputEnabled( bKBInput );
+ pPanel->SetMouseInputEnabled( bMouseInput );
+ // Don't adopt the parent's proportionalness
+ pPanel->SetProportional( true );
+ }
+}
+
+void CMMDashboardParentManager::AttachToTopMostPopup()
+{
+ // Not being used. Hide it.
+ if ( m_pHUDPopup )
+ {
+ m_pHUDPopup->SetVisible( false );
+ }
+
+ FOR_EACH_VEC( m_vecPanels, i )
+ {
+ Panel *pPanel = m_vecPanels[ i ];
+ // No longer a popup
+ surface()->ReleasePanel( pPanel->GetVPanel() );
+ ((VPanel*)pPanel->GetVPanel())->SetPopup( false );
+
+ if ( m_vecFullscreenPopups.Count() )
+ {
+ pPanel->SetParent( m_vecFullscreenPopups.Tail() );
+ }
+ else
+ {
+ pPanel->SetParent( enginevgui->GetPanel( PANEL_GAMEUIDLL ) );
+ }
+ pPanel->MoveToFront();
+ // Don't adopt the parent's proportionalness
+ pPanel->SetProportional( true );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Snag the singleton CMMDashboardParentManager
+//-----------------------------------------------------------------------------
+CMMDashboardParentManager* GetMMDashboardParentManager()
+{
+ static CMMDashboardParentManager* s_pParentManager = NULL;
+ if ( !s_pParentManager )
+ {
+ s_pParentManager = new CMMDashboardParentManager();
+ }
+
+ return s_pParentManager;
+}
+
+
+void CTFMatchmakingPopup::OnEnter()
+{
+ MMDashboardSpew( "Entering state %s\n", GetName() );
+
+ Update();
+
+ SetCollapsed( false );
+}
+
+void CTFMatchmakingPopup::OnUpdate()
+{
+}
+
+void CTFMatchmakingPopup::OnExit()
+{
+ MMDashboardSpew( "Exiting state %s\n", GetName() );
+ SetCollapsed( true );
+}
+
+
+void CTFMatchmakingPopup::Update()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFMatchmakingPopup::CTFMatchmakingPopup( const char* pszName, const char* pszResFile )
+ : CExpandablePanel( NULL, pszName )
+ , m_pszResFile( pszResFile )
+ , m_bActive( false )
+{
+ vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme");
+ SetScheme(scheme);
+ ivgui()->AddTickSignal( GetVPanel(), 100 );
+
+ GetMMDashboardParentManager()->AddPanel( this );
+ SetKeyBoardInputEnabled( false );
+
+ SetProportional( true );
+
+ ListenForGameEvent( "rematch_failed_to_create" );
+ ListenForGameEvent( "party_updated" );
+}
+
+CTFMatchmakingPopup::~CTFMatchmakingPopup()
+{
+ GetMMDashboardParentManager()->RemovePanel( this );
+}
+
+void CTFMatchmakingPopup::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ SetMouseInputEnabled( true );
+ LoadControlSettings( m_pszResFile );
+
+ // This cannot ever be true or else things get weird when in-game
+ SetKeyBoardInputEnabled( false );
+
+ if ( m_bActive )
+ {
+ OnEnter();
+ }
+ else
+ {
+ OnExit();
+ }
+
+ GetMMDashboardParentManager()->UpdateParenting();
+}
+
+void CTFMatchmakingPopup::OnThink()
+{
+ BaseClass::OnThink();
+
+ // Move us to be touching the bottom of the dashboard panel
+ // These panels have no relation whatsoever, so we're doing this manually
+ Panel* pDashboard = GetMMDashboard();
+ int nNewYPos = Max( pDashboard->GetYPos() + pDashboard->GetTall() - YRES(10), YRES(-5) );
+ SetPos( GetXPos(), nNewYPos );
+
+ if ( m_bActive )
+ {
+ OnUpdate();
+ }
+}
+
+void CTFMatchmakingPopup::OnTick()
+{
+ BaseClass::OnTick();
+
+ bool bShouldBeActive = ShouldBeActve();
+ if ( bShouldBeActive != m_bActive )
+ {
+ if ( bShouldBeActive )
+ {
+ m_bActive = true;
+ OnEnter();
+ }
+ else
+ {
+ m_bActive = false;
+ OnExit();
+ }
+ }
+
+ SetMouseInputEnabled( ShouldBeActve() );
+ SetKeyBoardInputEnabled( false ); // Never
+}
+
+
+void CTFMatchmakingPopup::OnCommand( const char *command )
+{
+ if ( FStrEq( "join_match", command ) )
+ {
+ JoinMatch();
+ }
+ else if ( FStrEq( "abandon_match", command ) )
+ {
+ GTFGCClientSystem()->RejoinLobby( false );
+ }
+ else if ( FStrEq( "leave_queue", command ) )
+ {
+ // Only the leader can leave the queue
+ if ( GTFGCClientSystem()->BIsPartyLeader() )
+ {
+ switch( GTFGCClientSystem()->GetSearchMode() )
+ {
+ case TF_Matchmaking_LADDER:
+ GTFGCClientSystem()->RequestSelectWizardStep( TF_Matchmaking_WizardStep_LADDER );
+ break;
+
+ case TF_Matchmaking_CASUAL:
+ GTFGCClientSystem()->RequestSelectWizardStep( TF_Matchmaking_WizardStep_CASUAL );
+ break;
+
+ default:
+ // Unhandled
+ Assert( false );
+ break;
+ };
+ }
+ }
+ else if( FStrEq( "rematch", command ) )
+ {
+ if ( !GTFGCClientSystem()->BIsPartyLeader() )
+ return;
+
+ engine->ClientCmd( "rematch_vote 2" );
+ }
+ else if ( FStrEq( "new_match", command ) )
+ {
+ if ( !GTFGCClientSystem()->BIsPartyLeader() )
+ return;
+
+ GTFGCClientSystem()->RequestSelectWizardStep( TF_Matchmaking_WizardStep_SEARCHING );
+ engine->ClientCmd( "rematch_vote 1" );
+ }
+ else if ( FStrEq( "leave_party", command ) )
+ {
+ // Leave current party and create a new one!
+ GTFGCClientSystem()->SendExitMatchmaking( false );
+ return;
+ }
+}
+
+
+void CTFMatchmakingPopup::FireGameEvent( IGameEvent *pEvent )
+{
+ if ( FStrEq( pEvent->GetName(), "rematch_failed_to_create" ) )
+ {
+ // If the GC failed to create our rematch, then go ahead and requeue
+ if ( !GTFGCClientSystem()->BIsPartyLeader() )
+ return;
+
+ GTFGCClientSystem()->RequestSelectWizardStep( TF_Matchmaking_WizardStep_SEARCHING );
+ }
+ else if ( FStrEq( pEvent->GetName(), "party_updated" ) )
+ {
+ if ( ShouldBeActve() )
+ {
+ Update();
+ }
+ }
+}
+
+
+#ifdef STAGING_ONLY
+CON_COMMAND( reload_mm_popup, "Reload the mm popup panel. Pass any 2nd argument to recreate the panel." )
+{
+ bool bRecreate = false;
+ if ( args.ArgC() == 2 )
+ {
+ bRecreate = true;
+ }
+
+ auto& vecPopups = CreateMMPopupPanels( bRecreate );
+
+ if ( !bRecreate )
+ {
+ FOR_EACH_VEC( vecPopups, i )
+ {
+ vecPopups[ i ]->InvalidateLayout( true, true );
+ }
+ }
+}
+
+CON_COMMAND( reload_mm_dashboard, "Reload the mm join panel." )
+{
+ GetMMDashboard()->InvalidateLayout( true, true );
+}
+#endif
+
+
+CTFMatchmakingDashboard::CTFMatchmakingDashboard()
+ : CExpandablePanel( NULL, "MMDashboard" )
+{
+ SetKeyBoardInputEnabled( false );
+ ivgui()->AddTickSignal( GetVPanel(), 100 );
+
+ GetMMDashboardParentManager()->AddPanel( this );
+
+ CreateMMPopupPanels();
+
+ vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme");
+ SetScheme(scheme);
+ SetProportional( true );
+}
+
+CTFMatchmakingDashboard::~CTFMatchmakingDashboard()
+{
+ GetMMDashboardParentManager()->RemovePanel( this );
+}
+
+void CTFMatchmakingDashboard::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ SetMouseInputEnabled( true );
+ LoadControlSettings( "resource/UI/MatchMakingDashboard.res" );
+
+ // This cannot ever be true or else things get weird when in-game
+ SetKeyBoardInputEnabled( false );
+
+ GetMMDashboardParentManager()->UpdateParenting();
+}
+
+void CTFMatchmakingDashboard::OnCommand( const char *command )
+{
+ if ( FStrEq( command, "disconnect" ) )
+ {
+ CTFParty* pParty = GTFGCClientSystem()->GetParty();
+ bool bInPartyOfMany = pParty && pParty->GetNumMembers() > 1;
+
+ const IMatchGroupDescription* pMatchDesc = GetMatchGroupDescription( TFGameRules()->GetCurrentMatchGroup() );
+ if ( pMatchDesc && pMatchDesc->BShouldAutomaticallyRequeueOnMatchEnd() && !bInPartyOfMany )
+ {
+ // If this is an auto-requeue match type, then assume hitting the "Disconnect" button
+ // means you are done playing entirely with MM. Close out to the main menu.
+ bool bNoPenalty = ( GTFGCClientSystem()->GetAssignedMatchAbandonStatus() != k_EAbandonGameStatus_AbandonWithPenalty );
+ if ( bNoPenalty )
+ {
+ GTFGCClientSystem()->EndMatchmaking( true );
+ }
+ else
+ {
+ // Prompt if this would be considered an abandon with a penalty
+ CTFDisconnectConfirmDialog *pDialog = BuildDisconnectConfirmDialog();
+ if ( pDialog )
+ {
+ pDialog->Show();
+ }
+ }
+ }
+ else
+ {
+ // Go back to the MM screens. The party leader will request the right wizard state
+ switch( GTFGCClientSystem()->GetSearchMode() )
+ {
+ case TF_Matchmaking_LADDER:
+ if ( GTFGCClientSystem()->BIsPartyLeader() )
+ {
+ GTFGCClientSystem()->RequestSelectWizardStep( TF_Matchmaking_WizardStep_LADDER );
+ }
+ engine->ClientCmd_Unrestricted( "OpenMatchmakingLobby ladder" );
+ break;
+
+ case TF_Matchmaking_CASUAL:
+ if ( GTFGCClientSystem()->BIsPartyLeader() )
+ {
+ GTFGCClientSystem()->RequestSelectWizardStep( TF_Matchmaking_WizardStep_CASUAL );
+ }
+ engine->ClientCmd_Unrestricted( "OpenMatchmakingLobby casual" );
+ break;
+
+ default:
+ // Unhandled
+ GTFGCClientSystem()->EndMatchmaking();
+ Assert( false );
+ break;
+ };
+ }
+
+ // Disconnect from the server
+ engine->DisconnectInternal();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Figure out if we should be visible and require mouse input
+//-----------------------------------------------------------------------------
+void CTFMatchmakingDashboard::OnTick()
+{
+ bool bInEndOfMatch = TFGameRules() && TFGameRules()->State_Get() == GR_STATE_GAME_OVER;
+
+ const IMatchGroupDescription* pMatchDesc = GetMatchGroupDescription( TFGameRules() ? TFGameRules()->GetCurrentMatchGroup() : k_nMatchGroup_Invalid );
+ bool bShouldBeVisible = GTFGCClientSystem()->BConnectedToMatchServer( false )
+ && bInEndOfMatch
+ && pMatchDesc
+ && pMatchDesc->BUsesDashboard();
+
+#ifdef STAGING_ONLY
+ bShouldBeVisible |= tf_mm_dashboard_force_show.GetBool();
+#endif
+
+ if ( BIsExpanded() && !bShouldBeVisible )
+ {
+ SetCollapsed( true );
+ }
+ else if ( !BIsExpanded() && bShouldBeVisible )
+ {
+ SetCollapsed( false );
+ }
+
+ SetKeyBoardInputEnabled( false );
+ SetMouseInputEnabled( BIsExpanded() );
+}
+
+CUtlVector< IMMPopupFactory* > IMMPopupFactory::s_vecPopupFactories;
+
+//-----------------------------------------------------------------------------
+// Purpose: Snag the singleton CTFMatchmakingPopup
+//-----------------------------------------------------------------------------
+CUtlVector< CTFMatchmakingPopup* >& CreateMMPopupPanels( bool bRecreate /*= false*/ )
+{
+ static CUtlVector< CTFMatchmakingPopup* > s_vecPopups;
+
+ if ( bRecreate && s_vecPopups.Count() )
+ {
+ FOR_EACH_VEC( s_vecPopups, i )
+ {
+ s_vecPopups[ i ]->MarkForDeletion();
+ }
+ s_vecPopups.Purge();
+ }
+
+
+ if ( s_vecPopups.IsEmpty() )
+ {
+ FOR_EACH_VEC( IMMPopupFactory::s_vecPopupFactories, i )
+ {
+ s_vecPopups.AddToTail( IMMPopupFactory::s_vecPopupFactories[i]->Create() );
+ }
+ }
+
+ return s_vecPopups;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Snag the singleton CTFMatchmakingDashboard
+//-----------------------------------------------------------------------------
+CTFMatchmakingDashboard* GetMMDashboard()
+{
+ static CTFMatchmakingDashboard* s_pDashboardPanel = NULL;
+ if ( !s_pDashboardPanel )
+ {
+ s_pDashboardPanel = new CTFMatchmakingDashboard();
+ }
+
+ return s_pDashboardPanel;
+}