1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
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)";
}
|