summaryrefslogtreecommitdiff
path: root/game/shared/tf/tf_matchmaking_shared.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/shared/tf/tf_matchmaking_shared.cpp')
-rw-r--r--game/shared/tf/tf_matchmaking_shared.cpp330
1 files changed, 330 insertions, 0 deletions
diff --git a/game/shared/tf/tf_matchmaking_shared.cpp b/game/shared/tf/tf_matchmaking_shared.cpp
new file mode 100644
index 0000000..b44d30f
--- /dev/null
+++ b/game/shared/tf/tf_matchmaking_shared.cpp
@@ -0,0 +1,330 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Matchmaking stuff shared between GC and gameserver / client
+//
+//=============================================================================
+
+#include "cbase.h"
+#include "tf_matchmaking_shared.h"
+#include "tf_match_description.h"
+#include "tf_ladder_data.h"
+
+#ifdef GC_DLL
+#include "tf_lobbymanager.h"
+#include "tf_partymanager.h"
+#include "tf_party.h"
+#endif
+
+#ifdef CLIENT_DLL
+#include "tf_gc_client.h"
+#include "tf_gamerules.h"
+#endif
+
+#ifdef GAME_DLL
+#include "tf_gc_server.h"
+#include "tf_gamerules.h"
+#include "tf_party.h"
+#endif
+
+const char *s_pszMatchGroups[] =
+{
+ "MatchGroup_MvM_Practice",
+ "MatchGroup_MvM_MannUp",
+
+ "MatchGroup_Ladder_6v6",
+ "MatchGroup_Ladder_9v9",
+ "MatchGroup_Ladder_12v12",
+
+ "MatchGroup_Casual_6v6",
+ "MatchGroup_Casual_9v9",
+ "MatchGroup_Casual_12v12",
+};
+
+COMPILE_TIME_ASSERT( ARRAYSIZE( s_pszMatchGroups ) == k_nMatchGroup_Count );
+
+#ifdef GC_DLL
+void On6v6MatchSizeChanged( IConVar *pConVar, const char *pOldString, float flOldValue )
+{
+ if ( !GGCBase()->BIsInLogonSurge() && !GGCTF()->GetIsShuttingDown() && TFLobbyManager()->GetMatchmaker() )
+ {
+ TFLobbyManager()->GetMatchmaker()->timeRemove6v6LadderGroupsExpire = CRTime::RTime32DateAdd( CRTime::RTime32TimeCur(), 10.f, k_ETimeUnitSecond );
+ }
+}
+#endif
+
+#if !defined GC_DLL
+ #define GCConVar ConVar
+ #define FCVAR_MATCHSIZE_THING ( FCVAR_REPLICATED )
+#else
+ #define FCVAR_MATCHSIZE_THING 0
+#endif
+
+GCConVar tf_mm_match_size_mvm( "tf_mm_match_size_mvm", "6", FCVAR_MATCHSIZE_THING,
+ "How many players in an MvM matchmade group?" );
+GCConVar tf_mm_match_size_ladder_6v6( "tf_mm_match_size_ladder_6v6", "12", FCVAR_MATCHSIZE_THING,
+ "Number of players required to play a 6v6 ladder game.", true, 1, true, 12
+#ifdef GC_DLL
+ , On6v6MatchSizeChanged
+#endif
+ );
+
+GCConVar tf_mm_match_size_ladder_9v9( "tf_mm_match_size_ladder_9v9", "18", FCVAR_MATCHSIZE_THING,
+ "Number of players required to play a 9v9 ladder game." );
+GCConVar tf_mm_match_size_ladder_12v12( "tf_mm_match_size_ladder_12v12", "24", FCVAR_MATCHSIZE_THING,
+ "Number of players required to play a 12v12 ladder game." );
+GCConVar tf_mm_match_size_ladder_12v12_minimum( "tf_mm_match_size_ladder_12v12_minimum", "12", FCVAR_MATCHSIZE_THING,
+ "Specifies the minimum number of players needed to launch a 12v12 match. Set to -1 to disable." );
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Init internal bitvec with ints from the protobuf message
+//-----------------------------------------------------------------------------
+CCasualCriteriaHelper::CCasualCriteriaHelper( const CMsgCasualMatchmakingSearchCriteria& criteria )
+{
+ m_mapsBits.Resize( GetItemSchema()->GetMasterMapsList().Count(), true );
+ Assert( m_mapsBits.GetNumDWords() >= criteria.selected_maps_bits_size() );
+
+ for( int i=0; i < criteria.selected_maps_bits_size() && i < m_mapsBits.GetNumDWords(); ++i )
+ {
+ m_mapsBits.SetDWord( i , criteria.selected_maps_bits( i ) );
+ }
+
+ // validate all of the bits to make sure the maps are in valid categories
+ int nNumBits = m_mapsBits.GetNumBits();
+ for( int i=0; i < nNumBits; ++i )
+ {
+ if ( m_mapsBits.IsBitSet( i ) == false )
+ continue;
+
+ if ( !IsMapInValidCategory( i ) )
+ {
+ const MapDef_t* pMap = GetItemSchema()->GetMasterMapDefByIndex( i );
+ if ( pMap )
+ {
+ DevMsg( "CCasualCriteriaHelper: Map %s is selected, but not in any valid game modes!\n", pMap->pszMapName );
+ }
+ SetMapSelected( i, false );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CCasualCriteriaHelper::IsMapSelected( const MapDef_t* pMapDef ) const
+{
+ if ( !pMapDef )
+ return false;
+
+ return IsMapSelected( pMapDef->m_nDefIndex );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check if bit is selected
+//-----------------------------------------------------------------------------
+bool CCasualCriteriaHelper::IsMapSelected( const uint32 nMapDefIndex ) const
+{
+ return m_mapsBits.IsBitSet( nMapDefIndex );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CCasualCriteriaHelper::IsMapInValidCategory( uint32 nMapDefIndex ) const
+{
+ Assert( (int)nMapDefIndex < m_mapsBits.GetNumBits() );
+
+ const MapDef_t* pMap = GetItemSchema()->GetMasterMapDefByIndex( nMapDefIndex );
+ if ( !pMap || pMap->m_vecAssociatedGameCategories.Count() == 0 )
+ {
+ return false;
+ }
+
+ // Make sure this map is in at least one category that's in a casual matchmaking group
+ FOR_EACH_VEC( pMap->m_vecAssociatedGameCategories, j )
+ {
+ const SchemaGameCategory_t* pCategory = GetItemSchema()->GetGameCategory( pMap->m_vecAssociatedGameCategories[j] );
+ const SchemaMMGroup_t* pMMGroup = pCategory->m_pMMGroup;
+
+ // Need to have active maps in a match making group
+ if ( !pMMGroup || ( pCategory->m_vecEnabledMaps.Count() == 0 ) || ( !pCategory->PassesRestrictions() ) )
+ {
+ continue;
+ }
+
+ // and the matchmaking group needs to be Special Events, Core or Alternative (not Comp)
+ if ( pMMGroup->m_eMMGroup == kMatchmakingType_SpecialEvents || pMMGroup->m_eMMGroup == kMatchmakingType_Core || pMMGroup->m_eMMGroup == kMatchmakingType_Alternative )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check if this criteria is well formed
+//-----------------------------------------------------------------------------
+bool CCasualCriteriaHelper::IsValid() const
+{
+ bool bValidMapSeen = false;
+
+ int nNumBits = m_mapsBits.GetNumBits();
+ for( int i=0; i < nNumBits; ++i )
+ {
+ if ( m_mapsBits.IsBitSet( i ) == false )
+ continue;
+
+ if ( IsMapInValidCategory( i ) )
+ {
+ bValidMapSeen = true;
+ }
+ }
+
+ return bValidMapSeen;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Turn helper back into protobuf message
+//-----------------------------------------------------------------------------
+CMsgCasualMatchmakingSearchCriteria CCasualCriteriaHelper::GetCasualCriteria() const
+{
+ CMsgCasualMatchmakingSearchCriteria outCriteria;
+ for( int i=0; i < m_mapsBits.GetNumDWords(); ++i )
+ {
+ outCriteria.add_selected_maps_bits( m_mapsBits.GetDWord( i ) );
+ }
+
+ return outCriteria;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Intersection of this criteria and another
+//-----------------------------------------------------------------------------
+void CCasualCriteriaHelper::Intersect( const CMsgCasualMatchmakingSearchCriteria& otherCriteria )
+{
+ CCasualCriteriaHelper otherHelper( otherCriteria );
+ m_mapsBits.And( otherHelper.m_mapsBits, &m_mapsBits );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Flip a specific map bit
+//-----------------------------------------------------------------------------
+bool CCasualCriteriaHelper::SetMapSelected( uint32 nMapDefIndex, bool bSelected )
+{
+ Assert( (int)nMapDefIndex < m_mapsBits.GetNumBits() );
+
+ if ( bSelected && !IsMapInValidCategory( nMapDefIndex ) )
+ {
+ const MapDef_t* pMap = GetItemSchema()->GetMasterMapDefByIndex( nMapDefIndex );
+ if ( pMap )
+ {
+ DevMsg( "CCasualCriteriaHelper: Attempting to set map %s as selected, but not in any valid game modes!\n", pMap->pszMapName );
+ }
+ return false;
+ }
+
+ m_mapsBits.Set( (int)nMapDefIndex, bSelected );
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets all bits to zero
+//-----------------------------------------------------------------------------
+void CCasualCriteriaHelper::Clear( void )
+{
+ m_mapsBits.ClearAll();
+}
+
+//
+// MvM Missions
+//
+
+CMvMMissionSet::CMvMMissionSet() { Clear(); }
+CMvMMissionSet::CMvMMissionSet( const CMvMMissionSet &x ) { m_bits = x.m_bits; }
+CMvMMissionSet::~CMvMMissionSet() {}
+void CMvMMissionSet::operator=( const CMvMMissionSet &x ) { m_bits = x.m_bits; }
+void CMvMMissionSet::Clear() { m_bits = 0; }
+bool CMvMMissionSet::operator==( const CMvMMissionSet &x ) const { return m_bits == x.m_bits; }
+
+void CMvMMissionSet::SetMissionBySchemaIndex( int idxMission, bool flag )
+{
+ Assert( idxMission >= 0 && idxMission < GetItemSchema()->GetMvmMissions().Count() );
+ uint64 mask = ( (uint64)1 << (unsigned)idxMission );
+ if ( flag )
+ m_bits |= mask;
+ else
+ m_bits &= ~mask;
+}
+
+bool CMvMMissionSet::GetMissionBySchemaIndex( int idxMission ) const
+{
+ // Bogus index?
+ if ( idxMission == k_iMvmMissionIndex_NotInSchema )
+ return false;
+ if ( idxMission < 0 || idxMission >= GetItemSchema()->GetMvmMissions().Count() )
+ {
+ Assert( idxMission >= 0 );
+ Assert( idxMission < GetItemSchema()->GetMvmMissions().Count() );
+ return false;
+ }
+
+ // Check the bit
+ uint64 mask = ( (uint64)1 << (unsigned)idxMission );
+ return ( m_bits & mask ) != 0;
+}
+
+void CMvMMissionSet::Intersect( const CMvMMissionSet &x )
+{
+ m_bits &= x.m_bits;
+}
+
+bool CMvMMissionSet::HasIntersection( const CMvMMissionSet &x ) const
+{
+ return ( m_bits & x.m_bits ) != 0;
+}
+
+bool CMvMMissionSet::IsEmpty() const
+{
+ return ( m_bits == 0 );
+}
+
+const char *GetMatchGroupName( EMatchGroup eMatchGroup )
+{
+ switch ( eMatchGroup )
+ {
+ case k_nMatchGroup_Invalid: return "(Invalid)";
+ case k_nMatchGroup_MvM_Practice: return "MvM Practice";
+ case k_nMatchGroup_MvM_MannUp: return "MvM MannUp";
+ case k_nMatchGroup_Ladder_6v6: return "6v6 Ladder Match";
+ case k_nMatchGroup_Ladder_9v9: return "9v9 Ladder Match";
+ case k_nMatchGroup_Ladder_12v12: return "12v12 Ladder Match";
+ case k_nMatchGroup_Casual_6v6: return "6v6 Casual Match";
+ case k_nMatchGroup_Casual_9v9: return "9v9 Casual Match";
+ case k_nMatchGroup_Casual_12v12: return "12v12 Casual Match";
+ }
+
+ AssertMsg1( false, "Invalid match group %d", eMatchGroup );
+ return "(Invalid match group)";
+}
+
+const char *GetServerPoolName( int iServerPool )
+{
+ switch ( iServerPool )
+ {
+ case k_nGameServerPool_MvM_Practice_Incomplete_Match: return "MvM Boot Camp Active";
+ case k_nGameServerPool_MvM_MannUp_Incomplete_Match: return "MvM MannUp Active";
+ case k_nGameServerPool_Casual_6v6_Incomplete_Match: return "Casual 6v6 Active";
+ case k_nGameServerPool_Casual_9v9_Incomplete_Match: return "Casual 9v9 Active";
+ case k_nGameServerPool_Casual_12v12_Incomplete_Match: return "Casual 12v12 Active";
+
+ case k_nGameServerPool_MvM_Practice_Full: return "MvM Boot Camp Full";
+ case k_nGameServerPool_MvM_MannUp_Full: return "MvM MannUp Full";
+ case k_nGameServerPool_Casual_6v6_Full: return "Casual 6v6 Full";
+ case k_nGameServerPool_Casual_9v9_Full: return "Casual 9v9 Full";
+ case k_nGameServerPool_Casual_12v12_Full: return "Casual 12v12 Full";
+ }
+
+ AssertMsg1( false, "Invalid server pool %d", iServerPool );
+ return "(Invalid pool index)";
+}