//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // //============================================================================= #ifndef TF_MATCH_DESCRIPTION_H #define TF_MATCH_DESCRIPTION_H #ifdef _WIN32 #pragma once #endif #include "tf_matchmaking_shared.h" #ifdef CLIENT_DLL #include "basemodel_panel.h" #endif // CLIENT_DLL #ifdef GAME_DLL // Can't foward declare CMatchInfo::PlayerMatchData_t because C++. Bummer. #include "tf_gc_server.h" #endif #ifdef GC_DLL class CTFLobby; class CTFParty; struct MatchDescription_t; struct MatchParty_t; #endif class CSOTFLadderData; enum EMatchType_t { MATCH_TYPE_NONE = 0, MATCH_TYPE_MVM, MATCH_TYPE_COMPETITIVE, MATCH_TYPE_CASUAL }; struct LevelInfo_t { uint32 m_nLevelNum; uint32 m_nStartXP; // Inclusive uint32 m_nEndXP; // Non-inclusive const char* m_pszLevelIcon; // Kill this when we do models const char* m_pszLevelTitle; const char* m_pszLevelUpSound; const char* m_pszLobbyBackgroundImage; }; struct XPSourceDef_t { const char* m_pszSoundName; const char* m_pszFormattingLocToken; const char* m_pszTypeLocToken; float m_flValueMultiplier; }; extern const XPSourceDef_t g_XPSourceDefs[ CMsgTFXPSource_XPSourceType_NUM_SOURCE_TYPES ]; class IProgressionDesc { public: IProgressionDesc( EMatchGroup eMatchGroup , const char* pszBadgeName , const char* pszProgressionResFile , const char* pszLevelToken ); #ifdef CLIENT_DLL virtual void SetupBadgePanel( CBaseModelPanel *pModelPanel, const LevelInfo_t& level ) const = 0; virtual const uint32 GetLocalPlayerLastAckdExperience() const = 0; virtual const uint32 GetPlayerExperienceBySteamID( CSteamID steamid ) const = 0; virtual const LevelInfo_t& YieldingGetLevelForSteamID( const CSteamID& steamID ) const; #endif // CLIENT_DLL #if defined GC_DLL // XXX(JohnS): This should go away once XP is just a rating type, no need for match description to have different // implementations of how the job does it. virtual bool BYldAcknowledgePlayerXPOnTransaction( CSQLAccess &transaction, CTFSharedObjectCache *pLockedSOCache ) const = 0; // XXX(JohnS): Same, this is super specific and hacky. virtual const bool BRankXPIsActuallyPrimaryMMRating() const = 0; #endif // defined GC_DLL virtual const LevelInfo_t& GetLevelForExperience( uint32 nExperience ) const; const LevelInfo_t& GetLevelByNumber( uint32 nNumber ) const; uint32 GetNumLevels() const { return m_vecLevels.Count(); } #if defined GC_DLL || ( defined STAGING_ONLY && defined CLIENT_DLL ) virtual void DebugSpewLevels() const = 0; #endif const CUtlString m_strBadgeName; const char* m_pszLevelToken; const char* m_pszProgressionResFile; protected: #ifdef CLIENT_DLL void EnsureBadgePanelModel( CBaseModelPanel *pModelPanel ) const; #endif const EMatchGroup m_eMatchGroup; CUtlVector< LevelInfo_t > m_vecLevels; }; struct MatchDesc_t { EMatchMode m_eLateJoinMode; EMMPenaltyPool m_ePenaltyPool; bool m_bUsesSkillRatings; bool m_bSupportsLowPriorityQueue; bool m_bRequiresMatchID; const ConVar* m_pmm_required_score; bool m_bUseMatchHud; const char* m_pszExecFileName; const ConVar* m_pmm_match_group_size; const ConVar* m_pmm_match_group_size_minimum; // Optional EMatchType_t m_eMatchType; bool m_bShowPreRoundDoors; bool m_bShowPostRoundDoors; const char* m_pszMatchEndKickWarning; const char* m_pszMatchStartSound; bool m_bAutoReady; bool m_bShowRankIcons; bool m_bUseMatchSummaryStage; bool m_bDistributePerformanceMedals; bool m_bIsCompetitiveMode; bool m_bUseFirstBlood; bool m_bUseReducedBonusTime; bool m_bUseAutoBalance; bool m_bAllowTeamChange; bool m_bRandomWeaponCrits; bool m_bFixedWeaponSpread; // If we should not allow match to complete without a complete set of players. bool m_bRequireCompleteMatch; bool m_bTrustedServersOnly; bool m_bForceClientSettings; bool m_bAllowDrawingAtMatchSummary; bool m_bAllowSpecModeChange; bool m_bAutomaticallyRequeueAfterMatchEnds; bool m_bUsesMapVoteOnRoundEnd; bool m_bUsesXP; bool m_bUsesDashboardOnRoundEnd; bool m_bUsesSurveys; // Be strict about finding quality matches, for more-competitive matchgroups that want to prioritize match quality // over speed. bool m_bStrictMatchmakerScoring; }; class IMatchGroupDescription { public: IMatchGroupDescription( EMatchGroup eMatchGroup, const MatchDesc_t& params ) : m_eMatchGroup( eMatchGroup ) , m_params( params ) , m_pProgressionDesc( NULL ) {} #ifdef GC_DLL // What rating the matchmaker should use to evaluate players in this matchgroup virtual EMMRating PrimaryMMRatingBackend() const = 0; // What ratings match results in this ladder group should run updates on virtual const std::vector< EMMRating > &MatchResultRatingBackends() const = 0; // When creating a match from the first party, what to copy over virtual bool InitMatchFromParty( MatchDescription_t* pMatch, const MatchParty_t* pParty ) const = 0; // When finding late joiners for an already-in-play lobby virtual bool InitMatchFromLobby( MatchDescription_t* pMatch, CTFLobby* pLobby ) const = 0; // Sync a match party with a CTFParty virtual void SyncMatchParty( const CTFParty *pParty, MatchParty_t *pMatchParty ) const = 0; // A match has formed, what game mode paremeters do we want to set? (ie. MvM Popfile, 12v12 map, etc) virtual void SelectModeSpecificParameters( const MatchDescription_t* pMatch, CTFLobby* pLobby ) const = 0; // Get which server pool to use virtual int GetServerPoolIndex( EMatchGroup eGroup, EMMServerMode eMode ) const; // Get server details virtual void GetServerDetails( const CMsgGameServerMatchmakingStatus& msg, int& nChallengeIndex, const char* pszMap ) const = 0; virtual const char* GetUnauthorizedPartyReason( CTFParty* pParty ) const = 0; virtual void Dump( const char *pszLeader, int nSpewLevel, int nLogLevel, const MatchParty_t* pMatch ) const = 0; // // Threaded calls. These are called in work items, and should be pure functions // // Check if pMatch is compatible with pCandidateParty -- that is, if BIntersectMatchWithParty would succeed. virtual bool BThreadedPartyCompatibleWithMatch( const MatchDescription_t* pMatch, const MatchParty_t *pCurrentParty ) const = 0; // When adding a party to a match, what intersection of current state with the incoming party gets copied to the // match. This returns false if the party isn't compatible, e.g. if !BThreadedPartyCompatibleWithMatch virtual bool BThreadedIntersectMatchWithParty( MatchDescription_t* pMatch, const MatchParty_t* pParty ) const = 0; // Check if two parties are compatible, that is, if they could be added to the same match absent other criteria virtual bool BThreadedPartiesCompatible( const MatchParty_t *pLeftParty, const MatchParty_t *pRightParty ) const = 0; #endif #ifdef CLIENT_DLL virtual bool BGetRoundStartBannerParameters( int& nSkin, int& nBodyGroup ) const = 0; virtual bool BGetRoundDoorParameters( int& nSkin, int& nLogoBodyGroup ) const = 0; virtual const char *GetMapLoadBackgroundOverride( bool bWideScreen ) const = 0; #endif #ifdef GAME_DLL // ! Check return, we might fail to setup virtual bool InitServerSettingsForMatch( const CTFGSLobby* pLobby ) const; virtual void InitGameRulesSettings() const = 0; virtual void InitGameRulesSettingsPostEntity() const = 0; virtual void PostMatchClearServerSettings() const = 0; virtual bool ShouldRequestLateJoin() const = 0; virtual bool BMatchIsSafeToLeaveForPlayer( const CMatchInfo* pMatchInfo, const CMatchInfo::PlayerMatchData_t *pMatchPlayer ) const = 0; virtual bool BPlayWinMusic( int nWinningTeam, bool bGameOver ) const = 0; #endif // Accessors for param values inline int GetMatchSize() const { return m_params.m_pmm_match_group_size->GetInt(); } inline bool BShouldAutomaticallyRequeueOnMatchEnd() const { return m_params.m_bAutomaticallyRequeueAfterMatchEnds; } inline bool BUsesMapVoteAfterMatchEnds() const { return m_params.m_bUsesMapVoteOnRoundEnd; } inline bool BUsesXP() const { return m_params.m_bUsesXP; } inline bool BUsesDashboard() const { return m_params.m_bUsesDashboardOnRoundEnd; } inline bool BUsesStrictMatchmakerScoring() const { return m_params.m_bStrictMatchmakerScoring; } inline bool BRequiresCompleteMatches() const { return m_params.m_bRequireCompleteMatch; } inline bool BRequiresMatchID() const { return m_params.m_bRequiresMatchID; } // Meta-permissions that are based on other set flags // // Only match-vote modes need this ability right now inline bool BCanServerRequestNewMatchForLobby() const { return BUsesMapVoteAfterMatchEnds(); } // Auto-balance and anything that is allowed to roll new match lobbies needs to have this ability (for speculative // matches if the GC is unavailable). It should be possible to add a mode where we do rolling matches, but only // when the GC is responding, which would not need the unilateral-team-assignment ability inline bool BCanServerChangeMatchPlayerTeams() const { return BCanServerRequestNewMatchForLobby() || m_params.m_bUseAutoBalance; } #ifdef GC_DLL inline bool BUsesSkillRatings() const { return m_params.m_bUsesSkillRatings; } inline int GetMinimumMatchSize() const { int min = m_params.m_pmm_match_group_size_minimum ? m_params.m_pmm_match_group_size_minimum->GetInt() : -1; return ( min >= 0 ) ? min : GetMatchSize(); } inline bool BUsesSurveys() const { return m_params.m_bUsesSurveys; } #endif inline bool BIsTrustedServersOnly() const { return m_params.m_bTrustedServersOnly; } const EMatchGroup m_eMatchGroup; const MatchDesc_t m_params; const IProgressionDesc* m_pProgressionDesc; }; const IMatchGroupDescription* GetMatchGroupDescription( const EMatchGroup& eGroup ); #endif //TF_MATCH_DESCRIPTION_H