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.

351 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Matchmaking stuff shared between GC and gameserver / client
  4. //
  5. //=============================================================================
  6. #ifndef TF_MATCHMAKING_SHARED_H
  7. #define TF_MATCHMAKING_SHARED_H
  8. #ifdef _WIN32
  9. #pragma once
  10. #endif
  11. #include "tf_gcmessages.pb.h"
  12. class IMatchGroupDescription;
  13. #define NEXT_MAP_VOTE_OPTIONS 3
  14. // Replace this hard-coded value concept in order to support all bracket types (i.e. anything higher than 6v6, etc)
  15. // This increases a number of hard-coded data structures and so on, so beware
  16. #define MATCH_SIZE_MAX 24
  17. // Similarly, some hot path MM structures use this for fixed arrays. It should be the maximum number of players that
  18. // will ever be in a party and no larger.
  19. #define MAX_PARTY_SIZE 6
  20. // Range clients are allowed to pass up for custom ping tolerance
  21. // Currently matches CS:GO
  22. #define CUSTOM_PING_TOLERANCE_MIN 25
  23. #define CUSTOM_PING_TOLERANCE_MAX 350
  24. // XXX(JohnS): Before we can actually use other rating backends for matchmaking or display purposes, there are remaining
  25. // hard coded assumptions about where the primary rating is, and issues with e.g. Match_Result assuming the
  26. // backend in use *now* is what the match was created for, etc. I've sprinkled this around at all the
  27. // landmines I found while implementing the new rating backend, so... comment this out and fix everything
  28. // that breaks.
  29. static inline void FixmeMMRatingBackendSwapping() {}
  30. // Backend-agnostic storage type for rating data, so we're not manually passing pairs around to every rating-specific
  31. // interface when we inevitably decide to add a third.
  32. //
  33. // Keep in mind that it is much easier to query well structured data for reports & otherwise, so we should prefer
  34. // e.g. adding another value to packing two 16-bit ints in RatingSecondary for a new backend that needs more 16-bit
  35. // values. (The calculus may change if we end up with a backend that has eight 8-bit values, however)
  36. //
  37. // Schema objects that embed rating data: RatingHistory, RatingData
  38. // Proto objects that embed rating data: CSOTFRatingData
  39. struct MMRatingData_t {
  40. uint32_t unRatingPrimary;
  41. uint32_t unRatingSecondary;
  42. uint32_t unRatingTertiary;
  43. inline bool operator==(const MMRatingData_t &b) const
  44. { return this->unRatingPrimary == b.unRatingPrimary &&
  45. this->unRatingSecondary == b.unRatingSecondary &&
  46. this->unRatingTertiary == b.unRatingTertiary; }
  47. };
  48. // Stored value, don't re-order
  49. enum EMatchGroup
  50. {
  51. k_nMatchGroup_Invalid = -1,
  52. k_nMatchGroup_First = 0,
  53. k_nMatchGroup_MvM_Practice = 0,
  54. k_nMatchGroup_MvM_MannUp,
  55. k_nMatchGroup_Ladder_6v6,
  56. k_nMatchGroup_Ladder_9v9,
  57. k_nMatchGroup_Ladder_12v12,
  58. k_nMatchGroup_Casual_6v6,
  59. k_nMatchGroup_Casual_9v9,
  60. k_nMatchGroup_Casual_12v12,
  61. k_nMatchGroup_Count,
  62. // When adding a new matchgroup, add case handling to GetMatchSizeForMatchGroup(), GetMatchGroupName(), GetServerPoolName(), GetMaxLobbySizeForMatchGroup(), YldWebAPIServersByDataCenter()
  63. };
  64. // Stored value, don't re-order
  65. //
  66. // If you add a new backend, see ITFMMRatingBackend::GetRatingBackend -- you need to at least provide a GetDefault()
  67. enum EMMRating
  68. {
  69. k_nMMRating_LowestValue = -1,
  70. k_nMMRating_Invalid = -1,
  71. k_nMMRating_First = 0,
  72. k_nMMRating_6v6_DRILLO = 0,
  73. k_nMMRating_6v6_DRILLO_PlayerAcknowledged = 1,
  74. k_nMMRating_6v6_GLICKO = 2,
  75. k_nMMRating_12v12_DRILLO = 3,
  76. k_nMMRating_12v12_GLICKO = 4,
  77. k_nMMRating_Last = 4,
  78. };
  79. // This must be in the range of an int16 for database serialization
  80. COMPILE_TIME_ASSERT( k_nMMRating_LowestValue >= INT16_MIN );
  81. COMPILE_TIME_ASSERT( k_nMMRating_Last <= INT16_MAX );
  82. // Stored value, don't re-order
  83. enum EMMRatingSource
  84. {
  85. k_nMMRatingSource_LowestValue = -1,
  86. k_nMMRatingSource_Invalid = -1,
  87. k_nMMRatingSource_Match = 0, // Match result. Source ID is match ID
  88. k_nMMRatingSource_Admin = 1, // Admin command/manual adjustment. Source ID is probably 0 or something.
  89. k_nMMRatingSource_PlayerAcknowledge = 2, // For 'acknowledge' type ratings, the player acknowledged the value
  90. k_nMMRatingSource_ImportedOldSystem = 3, // For pre-history ratings, this source is used once for 'initial rating from old system'
  91. k_nMMRatingSource_Last = 3,
  92. };
  93. // This must be in the range of an int16 for database serialization
  94. COMPILE_TIME_ASSERT( k_nMMRatingSource_LowestValue >= INT16_MIN );
  95. COMPILE_TIME_ASSERT( k_nMMRatingSource_Last <= INT16_MAX );
  96. // Also update this guy if you do the thing
  97. const char *GetMatchGroupName( EMatchGroup eMatchGroup );
  98. // Probably a better place for this...
  99. enum ELadderLeaderboardTypes
  100. {
  101. LADDER_LEADERBOARDS_6V6 = 0,
  102. LADDER_LEADERBOARDS_PUBLIC,
  103. LADDER_LEADERBOARDS_9V9,
  104. LADDER_LEADERBOARDS_12V12,
  105. LADDER_LEADERBOARDS_MAX
  106. };
  107. // Late join modes
  108. enum EMatchMode
  109. {
  110. // Uninitialized/unknown
  111. eMatchMode_Invalid,
  112. // Not late join / don't use late join
  113. eMatchMode_MatchMaker_CompleteFromQueue,
  114. // The add-one-player-at-a-time mode that doesn't work with the new scoring system, but still used for MvM and other
  115. // old-scoring-system stuff.
  116. eMatchMode_MatchMaker_LateJoinDropIn,
  117. // The new late join mode that re-evaulates complete matches with the missing spot(s) filled.
  118. eMatchMode_MatchMaker_LateJoinMatchBased,
  119. // A match that is being manually crafted
  120. eMatchMode_Manual,
  121. };
  122. const EMatchGroup k_nMatchGroup_Ladder_First = k_nMatchGroup_Ladder_6v6;
  123. const EMatchGroup k_nMatchGroup_Ladder_Last = k_nMatchGroup_Ladder_12v12;
  124. const EMatchGroup k_nMatchGroup_Casual_First = k_nMatchGroup_Casual_6v6;
  125. const EMatchGroup k_nMatchGroup_Casual_Last = k_nMatchGroup_Casual_12v12;
  126. inline bool IsMvMMatchGroup( EMatchGroup eMatchGroup )
  127. {
  128. return ( eMatchGroup == k_nMatchGroup_MvM_Practice ) || ( eMatchGroup == k_nMatchGroup_MvM_MannUp );
  129. }
  130. inline bool IsLadderGroup( EMatchGroup eMatchGroup )
  131. {
  132. return ( eMatchGroup >= k_nMatchGroup_Ladder_First && eMatchGroup <= k_nMatchGroup_Ladder_Last )
  133. || ( eMatchGroup >= k_nMatchGroup_Casual_First && eMatchGroup <= k_nMatchGroup_Casual_Last );
  134. }
  135. inline bool IsCasualGroup( EMatchGroup eMatchGroup )
  136. {
  137. return ( eMatchGroup >= k_nMatchGroup_Casual_First ) && ( eMatchGroup <= k_nMatchGroup_Casual_Last );
  138. }
  139. inline bool IsMannUpGroup( EMatchGroup eMatchGroup )
  140. {
  141. switch ( eMatchGroup )
  142. {
  143. case k_nMatchGroup_MvM_Practice:
  144. return false;
  145. case k_nMatchGroup_MvM_MannUp:
  146. return true;
  147. case k_nMatchGroup_Ladder_6v6:
  148. case k_nMatchGroup_Ladder_9v9:
  149. case k_nMatchGroup_Ladder_12v12:
  150. return false;
  151. case k_nMatchGroup_Invalid:
  152. default:
  153. Assert( !"IsMannUpGroup called with invalid match group" );
  154. return false;
  155. }
  156. return false;
  157. }
  158. enum EMMServerMode
  159. {
  160. eMMServerMode_Idle,
  161. eMMServerMode_Incomplete_Match,
  162. eMMServerMode_Full,
  163. eMMServerMode_Count
  164. };
  165. // Separate penalty pools (and rules) for different classes of modes
  166. enum EMMPenaltyPool
  167. {
  168. eMMPenaltyPool_Invalid,
  169. eMMPenaltyPool_Casual, // Pool with lenient penalties for most casual/mainstream gamemodes
  170. eMMPenaltyPool_Ranked // Pool with strict and cumulative penalties for ranked gamemodes where abandons tank matches
  171. };
  172. enum
  173. {
  174. // !! This should match up with GetServerPoolIndex to map these between match groups and server pools
  175. // eMMServerMode_NotParticipating
  176. k_nGameServerPool_NotParticipating = -1,
  177. // eMMServerMode_Incomplete_Match
  178. k_nGameServerPool_MvM_Practice_Incomplete_Match = 0,
  179. k_nGameServerPool_MvM_MannUp_Incomplete_Match,
  180. k_nGameServerPool_Ladder_6v6_Incomplete_Match,
  181. k_nGameServerPool_Ladder_9v9_Incomplete_Match,
  182. k_nGameServerPool_Ladder_12v12_Incomplete_Match,
  183. k_nGameServerPool_Casual_6v6_Incomplete_Match,
  184. k_nGameServerPool_Casual_9v9_Incomplete_Match,
  185. k_nGameServerPool_Casual_12v12_Incomplete_Match,
  186. // eMMServerMode_Full
  187. k_nGameServerPool_MvM_Practice_Full,
  188. k_nGameServerPool_MvM_MannUp_Full,
  189. k_nGameServerPool_Ladder_6v6_Full,
  190. k_nGameServerPool_Ladder_9v9_Full,
  191. k_nGameServerPool_Ladder_12v12_Full,
  192. k_nGameServerPool_Casual_6v6_Full,
  193. k_nGameServerPool_Casual_9v9_Full,
  194. k_nGameServerPool_Casual_12v12_Full,
  195. // eMMServerMode_Idle
  196. k_nGameServerPool_Idle,
  197. // When adding a new matchgroup, add case handling to GetMatchSizeForMatchGroup(), GetMatchGroupName(), GetServerPoolName(), GetMaxLobbySizeForMatchGroup(), YldWebAPIServersByDataCenter()
  198. k_nGameServerPoolCountTotal,
  199. };
  200. // Also update this guy if you touch pools
  201. const char *GetServerPoolName( int iServerPool );
  202. const int k_nGameServerPool_Incomplete_Match_First = k_nGameServerPool_MvM_Practice_Incomplete_Match;
  203. const int k_nGameServerPool_Incomplete_Match_Last = k_nGameServerPool_Casual_12v12_Incomplete_Match;
  204. const int k_nGameServerPool_Full_First = k_nGameServerPool_MvM_Practice_Full;
  205. const int k_nGameServerPool_Full_Last = k_nGameServerPool_Casual_12v12_Full;
  206. COMPILE_TIME_ASSERT( k_nGameServerPool_Incomplete_Match_First + k_nMatchGroup_Count - 1 == k_nGameServerPool_Incomplete_Match_Last );
  207. COMPILE_TIME_ASSERT( k_nGameServerPool_Full_First + k_nMatchGroup_Count - 1 == k_nGameServerPool_Full_Last );
  208. inline bool IsIncompleteMatchPool( int nGameServerPool )
  209. {
  210. return nGameServerPool >= k_nGameServerPool_Incomplete_Match_First && nGameServerPool <= k_nGameServerPool_Incomplete_Match_Last;
  211. }
  212. // Stuff is simpler if we can set a max number of challenges in the schema
  213. #define MAX_MVM_CHALLENGES 64
  214. // Store a set of MvM challenges (search criteria, etc)
  215. class CMvMMissionSet
  216. {
  217. public:
  218. CMvMMissionSet();
  219. CMvMMissionSet( const CMvMMissionSet &x );
  220. ~CMvMMissionSet();
  221. void operator=( const CMvMMissionSet &x );
  222. bool operator==( const CMvMMissionSet &x ) const;
  223. /// Set to the empty set
  224. void Clear();
  225. /// get/set individual bits, based on index of the challenge in the schema
  226. void SetMissionBySchemaIndex( int iChallengeSchemaIndex, bool flag );
  227. bool GetMissionBySchemaIndex( int iChallengeSchemaIndex ) const;
  228. /// Intersect this set with the other set. Use IsEmpty()
  229. /// to see if this produced the empty set.
  230. void Intersect( const CMvMMissionSet &x );
  231. /// Return true if the two sets have a nonzero intersection. (Neither object is modified)
  232. bool HasIntersection( const CMvMMissionSet &x ) const;
  233. /// Return true if any challenges are selected
  234. bool IsEmpty() const;
  235. private:
  236. COMPILE_TIME_ASSERT( MAX_MVM_CHALLENGES <= 64 );
  237. // Just use a plain old uint64 for now. We can make this into a proper bitfield class at some point
  238. uint64 m_bits;
  239. };
  240. // Player Skill Ratings
  241. const int k_nDrilloRating_MinRatingAdjust = 1;
  242. const int k_nDrilloRating_MaxRatingAdjust = 100;
  243. const int k_nDrilloRating_Ladder_MaxRatingAdjust = 500;
  244. const int k_nDrilloRating_Ladder_MaxLossAdjust_LowRank = 100;
  245. const uint32 k_unDrilloRating_MaxDifference = 25000;
  246. const uint32 k_unDrilloRating_Min = 1;
  247. const uint32 k_unDrilloRating_Ladder_Min = 10000;
  248. const uint32 k_unDrilloRating_Max = 50000;
  249. const uint32 k_unDrilloRating_Avg = 20000;
  250. const uint32 k_unDrilloRating_Ladder_Start = 10000;
  251. const uint32 k_unDrilloRating_Ladder_LowSkill = 19500; // First 6 ranks ceiling
  252. const uint32 k_unDrilloRating_Ladder_HighSkill = 33001; // Last 6 ranks floor
  253. struct MapDef_t;
  254. //-----------------------------------------------------------------------------
  255. // Purpose: Wrapper class to make dealing with CMsgCasualMatchmakingSearchCriteria
  256. // much easier.
  257. //-----------------------------------------------------------------------------
  258. class CCasualCriteriaHelper
  259. {
  260. public:
  261. CCasualCriteriaHelper( const CMsgCasualMatchmakingSearchCriteria& criteria );
  262. bool IsMapSelected( const MapDef_t* pMapDef ) const;
  263. bool IsMapSelected( const uint32 nMapDefIndex ) const;
  264. bool IsValid() const;
  265. bool AnySelected() const { return !m_mapsBits.IsAllClear(); }
  266. CMsgCasualMatchmakingSearchCriteria GetCasualCriteria() const;
  267. void Intersect( const CMsgCasualMatchmakingSearchCriteria& otherCriteria );
  268. bool SetMapSelected( uint32 nMapDefIndex, bool bSelected );
  269. void Clear( void );
  270. private:
  271. bool IsMapInValidCategory( uint32 nMapDefIndex ) const;
  272. private:
  273. CLargeVarBitVec m_mapsBits;
  274. };
  275. // CSOTFLobby flags
  276. #define LOBBY_FLAG_LOWPRIORITY ( 1 << 0 )
  277. #define LOBBY_FLAG_REMATCH ( 1 << 1 )
  278. // CMsgGC_Match_Result match flags
  279. #define MATCH_FLAG_LOWPRIORITY ( 1 << 0 )
  280. #define MATCH_FLAG_REMATCH ( 1 << 1 )
  281. // CMsgGC_Match_Result player flags
  282. #define MATCH_FLAG_PLAYER_LEAVER ( 1 << 0 )
  283. #define MATCH_FLAG_PLAYER_LATEJOIN ( 1 << 1 )
  284. // Separate from LEAVER - was marked as an abandon and issued a penalty. You can be a leaver without being an
  285. // abandoner.
  286. #define MATCH_FLAG_PLAYER_ABANDONER ( 1 << 2 )
  287. #define MATCH_FLAG_PLAYER_PLAYED ( 1 << 3 ) // Did they stay long enough for the game to start?
  288. #endif // #ifndef TF_MATCHMAKING_SHARED_H