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.
540 lines
20 KiB
540 lines
20 KiB
5 years ago
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||
|
#ifndef TF_GC_SERVER_H
|
||
|
#define TF_GC_SERVER_H
|
||
|
#ifdef _WIN32
|
||
|
#pragma once
|
||
|
#endif
|
||
|
|
||
|
#if !defined( _X360 ) && !defined( NO_STEAM )
|
||
|
#include "steam/steam_api.h"
|
||
|
#include "steam/steam_gameserver.h"
|
||
|
#endif
|
||
|
|
||
|
//#include "tf_gc_common.h"
|
||
|
#include "gcsdk/gcclientsdk.h"
|
||
|
#include "playergroup.h"
|
||
|
//#include "dota_gamerules.h"
|
||
|
#include "gc_clientsystem.h"
|
||
|
#include "tf_gcmessages.h"
|
||
|
#include "GameEventListener.h"
|
||
|
#include "rtime.h"
|
||
|
#include "tf_shareddefs.h"
|
||
|
|
||
|
class CTFGSLobby;
|
||
|
class CTFParty;
|
||
|
|
||
|
//enum EDOTA_Uploading_Match_Stats
|
||
|
//{
|
||
|
// EDOTA_MATCH_STATS_IDLE,
|
||
|
// EDOTA_MATCH_STATS_UPLOADING,
|
||
|
// EDOTA_MATCH_STATS_UPLOAD_COMPLETE
|
||
|
//};
|
||
|
|
||
|
#ifdef ENABLE_GC_MATCHMAKING
|
||
|
|
||
|
class CMvMVictoryInfo
|
||
|
{
|
||
|
public:
|
||
|
int m_nLobbyId;
|
||
|
CUtlString m_sChallengeName;
|
||
|
#ifdef USE_MVM_TOUR
|
||
|
CUtlString m_sMannUpTourOfDuty;
|
||
|
#endif // USE_MVM_TOUR
|
||
|
CUtlVector<uint64> m_vPlayerIds;
|
||
|
CUtlVector<bool> m_vSquadSurplus;
|
||
|
RTime32 m_tEventTime;
|
||
|
|
||
|
void Init ( CTFGSLobby *pLobby );
|
||
|
};
|
||
|
|
||
|
class CMatchInfo
|
||
|
{
|
||
|
friend class CTFGCServerSystem;
|
||
|
public:
|
||
|
CMatchInfo( const CTFGSLobby *pLobby );
|
||
|
~CMatchInfo();
|
||
|
|
||
|
uint64 m_nMatchID;
|
||
|
uint64 m_nLobbyID;
|
||
|
EMatchGroup m_eMatchGroup;
|
||
|
uint32 m_uLobbyFlags;
|
||
|
uint32 m_uAverageRank;
|
||
|
RTime32 m_rtMatchCreated;
|
||
|
uint32 m_unEventTeamStatus;
|
||
|
bool m_bFirstPersonActive;
|
||
|
int m_nBotsAdded;
|
||
|
bool m_bServerCreated;
|
||
|
|
||
|
struct DailyStatsRankBucket_t
|
||
|
{
|
||
|
uint32 nRank;
|
||
|
uint32 nRecords;
|
||
|
uint32 nAvgScore;
|
||
|
uint32 nStDevScore;
|
||
|
uint32 nAvgKills;
|
||
|
uint32 nStDevKills;
|
||
|
uint32 nAvgDamage;
|
||
|
uint32 nStDevDamage;
|
||
|
uint32 nAvgHealing;
|
||
|
uint32 nStDevHealing;
|
||
|
uint32 nAvgSupport;
|
||
|
uint32 nStDevSupport;
|
||
|
};
|
||
|
|
||
|
struct PlayerMatchData_t
|
||
|
{
|
||
|
friend class CTFGCServerSystem;
|
||
|
friend class CMatchInfo;
|
||
|
PlayerMatchData_t( CSteamID steamID, const CTFLobbyMember *pMemberData )
|
||
|
: steamID( steamID )
|
||
|
, uPartyID( pMemberData->party_id() )
|
||
|
, eGCTeam( pMemberData->team() )
|
||
|
, bDropped( false )
|
||
|
, bConnected( false )
|
||
|
, rtJoinedMatch( CRTime::RTime32TimeCur() )
|
||
|
, nVoteKickAttempts( 0 )
|
||
|
, nDisconnectedSeconds( 0 )
|
||
|
, nScoreMedal( 0 )
|
||
|
, nKillsMedal( 0 )
|
||
|
, nDamageMedal( 0 )
|
||
|
, nHealingMedal( 0 )
|
||
|
, nSupportMedal( 0 )
|
||
|
, bLateJoin( false )
|
||
|
, nScore( 0 )
|
||
|
, bPlayed( false )
|
||
|
, unMMSkillRating( 0u )
|
||
|
, nDrilloRatingDelta( 0 )
|
||
|
, unClassesPlayed( 0u )
|
||
|
, rtLastActiveEvent( CRTime::RTime32TimeCur() )
|
||
|
, bAlwaysSafeToLeave( false )
|
||
|
, bEverConnected( false )
|
||
|
, bDropWasAbandon( false )
|
||
|
, eDropReason( TFMatchLeaveReason_UNSPECIFIED )
|
||
|
, nConnectingButNotActiveIndex( 0 )
|
||
|
, m_mapXPAccumulation( DefLessFunc( CMsgTFXPSource::XPSourceType ) )
|
||
|
{}
|
||
|
|
||
|
PlayerMatchData_t( const PlayerMatchData_t& rhs );
|
||
|
|
||
|
CSteamID steamID;
|
||
|
uint64 uPartyID;
|
||
|
TF_GC_TEAM eGCTeam;
|
||
|
|
||
|
// If true, this player was dropped from the match and is not part of the active lobby. This is important for
|
||
|
// cases where the GC connection is lost and the lobby state is stale.
|
||
|
bool bDropped;
|
||
|
bool bConnected;
|
||
|
// Timestamp player joined the match at. Not guaranteed to be the same instant the match was created, depending
|
||
|
// on how the GC does things.
|
||
|
RTime32 rtJoinedMatch;
|
||
|
|
||
|
uint32 nVoteKickAttempts;
|
||
|
|
||
|
// Number of cumulative seconds the player has been absent, *not* including the initial connect timeout. Used
|
||
|
// to determine when to award an abandon. We may do odd things like "comp" you some seconds on a second, later,
|
||
|
// disconnect, so this shouldn't be used for stats purposes.
|
||
|
int nDisconnectedSeconds;
|
||
|
|
||
|
int nScoreMedal;
|
||
|
int nKillsMedal;
|
||
|
int nDamageMedal;
|
||
|
int nHealingMedal;
|
||
|
int nSupportMedal;
|
||
|
|
||
|
bool bLateJoin;
|
||
|
int nScore;
|
||
|
bool bPlayed;
|
||
|
// This is a single-value skill rating given to each player by the GC
|
||
|
uint32 unMMSkillRating;
|
||
|
// This is the older drillo rating system that was done on the server. It is still sent up to the GC as the
|
||
|
// input to the drillo backend there. If we want to keep this long-term it should be moved to be a fully-gc
|
||
|
// backend like glicko
|
||
|
int nDrilloRatingDelta;
|
||
|
uint32 unClassesPlayed;
|
||
|
|
||
|
const CMsgTFXPSourceBreakdown& GetXPSources() const { return m_XPBreakdown; }
|
||
|
|
||
|
// Override releasing this player from obligation to this match beyond the normal abandon rules. Used by MvM mode
|
||
|
// for marking everyone who completes a wave as allowed to drop without penalty, for instance.
|
||
|
void MarkAlwaysSafeToLeave() { bAlwaysSafeToLeave = true; }
|
||
|
|
||
|
bool BDropWasAbandon() { return bDropped && bDropWasAbandon; }
|
||
|
TFMatchLeaveReason GetDropReason() { return bDropped ? eDropReason : TFMatchLeaveReason_UNSPECIFIED; }
|
||
|
RTime32 GetLastActiveEventTime( void ) { return rtLastActiveEvent; }
|
||
|
|
||
|
MM_PlayerConnectionState_t GetConnectionState() const;
|
||
|
void UpdateClassesPlayed( int nClass );
|
||
|
|
||
|
struct XPBonusPool_t
|
||
|
{
|
||
|
XPBonusPool_t()
|
||
|
: m_flMultiplier( 1.f )
|
||
|
, m_nBonusPoolRemaining( 0 )
|
||
|
{}
|
||
|
|
||
|
CMsgTFXPSource_XPSourceType m_eType;
|
||
|
|
||
|
// Only give up to this amount
|
||
|
int m_nBonusPoolRemaining;
|
||
|
// Give at this rate
|
||
|
float m_flMultiplier;
|
||
|
};
|
||
|
|
||
|
private:
|
||
|
|
||
|
void OnConnected( int nEntindex );
|
||
|
void OnActive();
|
||
|
|
||
|
// Last time the player changed between active (fully loaded in) and not-active. A player is active if
|
||
|
// ( bConnected && !nConnectingButNotActiveIndex )
|
||
|
RTime32 rtLastActiveEvent;
|
||
|
bool bAlwaysSafeToLeave;
|
||
|
bool bEverConnected;
|
||
|
// If dropped - was it an abandon and what was the reason.
|
||
|
bool bDropWasAbandon;
|
||
|
TFMatchLeaveReason eDropReason;
|
||
|
|
||
|
// Track the janky source-engine state between ClientConnect (when we allow them in) and ClientActive
|
||
|
int nConnectingButNotActiveIndex;
|
||
|
|
||
|
// XP accumulation for a player
|
||
|
CMsgTFXPSourceBreakdown m_XPBreakdown;
|
||
|
// The breakdown stores ints, but we need float precision or else we're going to round off a
|
||
|
// significant amount of XP as the match plays on.
|
||
|
CUtlMap< CMsgTFXPSource::XPSourceType, float > m_mapXPAccumulation;
|
||
|
|
||
|
CUtlVector< XPBonusPool_t > m_vecXPBonusPools;
|
||
|
};
|
||
|
|
||
|
enum RankStatType_t
|
||
|
{
|
||
|
RankStat_Invalid = -1,
|
||
|
RankStat_Score = 0,
|
||
|
RankStat_Kills,
|
||
|
RankStat_Damage,
|
||
|
RankStat_Healing,
|
||
|
RankStat_Support,
|
||
|
};
|
||
|
|
||
|
void SetDailyRankData( DailyStatsRankBucket_t vecRankData );
|
||
|
bool RequestGCRankData( void );
|
||
|
bool CalculatePlayerMatchRankData( void );
|
||
|
bool CalculateMatchSkillRatingAdjustments( int iWinningTeam );
|
||
|
const CMatchInfo::PlayerMatchData_t* GetMatchDataForPlayer( CSteamID steamID ) const;
|
||
|
CMatchInfo::PlayerMatchData_t* GetMatchDataForPlayer( CSteamID steamID );
|
||
|
|
||
|
// For iterating over all players. Index is relative to GetNumTotalMatchPlayers
|
||
|
CMatchInfo::PlayerMatchData_t* GetMatchDataForPlayer( int nPlayer );
|
||
|
|
||
|
// This is the total number of players we have match data for -- it may include dropped players not part of the
|
||
|
// match any longer.
|
||
|
int GetNumTotalMatchPlayers() const;
|
||
|
|
||
|
// Number of players still active in the match.
|
||
|
int GetNumActiveMatchPlayers() const;
|
||
|
|
||
|
// Number of players still active in the match for a specific team
|
||
|
int GetNumActiveMatchPlayersForTeam( int nTeam ) const;
|
||
|
|
||
|
// Total skill rating for a team
|
||
|
int GetTotalSkillRatingForTeam( int nTeam ) const;
|
||
|
|
||
|
// Subset of active match players who are currently connected
|
||
|
int GetNumConnectedMatchPlayers() const;
|
||
|
|
||
|
// Indicates that this is a stale match that is ending. In cases such as rolling matches, we never "end" a match,
|
||
|
// just roll into the next one, since "ended" matches indicate that we've terminated our relationship with the
|
||
|
// players/GC.
|
||
|
bool BMatchTerminated() const { return m_bMatchEnded; }
|
||
|
|
||
|
// Indicates we've sent a result for this match. The match may still be active if we're intending to use it to start
|
||
|
// a rolling match or other post-game activities.
|
||
|
bool BSentResult() const { return m_bSentResult; }
|
||
|
|
||
|
// The canonical size of this type of match. Can be passed from the GC and override the match description size.
|
||
|
uint32 GetCanonicalMatchSize() const;
|
||
|
|
||
|
const char *GetMatchMap() const { return m_strMapName.Length() ? m_strMapName.Get() : NULL; }
|
||
|
|
||
|
// Rewards the player with XP based on the count scaled by the XP per unit of that type.
|
||
|
// nCount here is the raw occurances of the action (ie. Points scored, Gold Medals Scored)
|
||
|
void GiveXPRewardToPlayerForAction( CSteamID steamID, CMsgTFXPSource::XPSourceType eType, int nCount );
|
||
|
// Directly assign the value
|
||
|
void GiveXPDirectly( CSteamID steamID, CMsgTFXPSource::XPSourceType eType, int nAmount, bool bCanAwardBonusXP = true );
|
||
|
// Give an XP bonus that increases
|
||
|
void GiveXPBonus( CSteamID steamID,
|
||
|
CMsgTFXPSource_XPSourceType eType,
|
||
|
float flMultipler,
|
||
|
int nBonusPool );
|
||
|
|
||
|
// Is this player allowed to leave the match without incurring an abandon right now
|
||
|
|
||
|
// TODO(JohnS): This should not go from true to false due to race conditions (players clicks DC, sees no warning,
|
||
|
// races with server deciding its unsafe again), but does for MvM late join. The GS-initiated late
|
||
|
// join rework would make it possible to fix that (once it enters too-low-to-latejoin state it stays
|
||
|
// there)
|
||
|
bool BPlayerSafeToLeaveMatch( CSteamID steamID );
|
||
|
|
||
|
protected:
|
||
|
int GetRankForStat( RankStatType_t statType, int nRankIndex, uint32 nValue );
|
||
|
float NormalDistributionCDF( float flValue, float flMu, float flSigma );
|
||
|
|
||
|
private:
|
||
|
CMatchInfo();
|
||
|
CMatchInfo( const CMatchInfo &otherinfo );
|
||
|
|
||
|
// Track a new player participating in our match
|
||
|
void AddPlayer( CSteamID steamID, const CTFLobbyMember *pMemberData, bool bIsLateJoin, int nEntindex, bool bActive );
|
||
|
// Or with an existing player to copy from (e.g. old match)
|
||
|
void AddPlayer( const PlayerMatchData_t &oldPlayer, int nEntIndex, bool bActive );
|
||
|
|
||
|
// Mark a player as dropped from the match
|
||
|
void DropPlayer( CSteamID steamID, TFMatchLeaveReason eReason, bool bWasAbandon );
|
||
|
void SetEnded() { m_bMatchEnded = true; }
|
||
|
|
||
|
CUtlVector < DailyStatsRankBucket_t > m_vDailyStatsRankData;
|
||
|
CUtlVector < PlayerMatchData_t* > m_vMatchRankData;
|
||
|
|
||
|
CUtlString m_strMapName;
|
||
|
bool m_bMatchEnded;
|
||
|
bool m_bSentResult;
|
||
|
// Canonical size for this match type, override passed from GC.
|
||
|
uint32 m_nGCMatchSize;
|
||
|
|
||
|
float m_flBronzePercentile;
|
||
|
float m_flSilverPercentile;
|
||
|
float m_flGoldPercentile;
|
||
|
};
|
||
|
|
||
|
class CTFGCServerSystem : public CGCClientSystem, public GCSDK::ISharedObjectListener, public IServerGCLobby, public CGameEventListener
|
||
|
{
|
||
|
DECLARE_CLASS_GAMEROOT( CTFGCServerSystem, CGCClientSystem );
|
||
|
|
||
|
// Messages that need to do callbacks
|
||
|
friend class ReliableMsgNewMatchForLobby;
|
||
|
friend class ReliableMsgChangeMatchPlayerTeams;
|
||
|
public:
|
||
|
CTFGCServerSystem( void );
|
||
|
~CTFGCServerSystem( void );
|
||
|
|
||
|
// CAutoGameSystemPerFrame
|
||
|
virtual bool Init() OVERRIDE;
|
||
|
virtual void LevelInitPreEntity() OVERRIDE;
|
||
|
virtual void LevelShutdownPostEntity() OVERRIDE;
|
||
|
virtual void Shutdown() OVERRIDE;
|
||
|
virtual void PreClientUpdate() OVERRIDE;
|
||
|
|
||
|
// uint8 FindItemID( CTF_Item *pItem );
|
||
|
void MatchSignOut();
|
||
|
// const char *GetMatchStartTimeString();
|
||
|
|
||
|
// void GameRules_State_Enter( DOTA_GameState newState );
|
||
|
|
||
|
void SetHibernation( bool bHibernating );
|
||
|
bool ShouldHideServer();
|
||
|
|
||
|
// ISharedObjectListener
|
||
|
virtual void SOCreated( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
|
||
|
virtual void PreSOUpdate( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { /* do nothing */ }
|
||
|
virtual void SOUpdated( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
|
||
|
virtual void PostSOUpdate( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { /* do nothing */ }
|
||
|
virtual void SODestroyed( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
|
||
|
virtual void SOCacheSubscribed( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { }
|
||
|
virtual void SOCacheUnsubscribed( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { }
|
||
|
|
||
|
void DumpLobby();
|
||
|
|
||
|
// IServerGCLobby methods
|
||
|
virtual bool HasLobby() const;
|
||
|
virtual bool SteamIDAllowedToConnect(const CSteamID &steamId) const;
|
||
|
virtual void UpdateServerDetails(void);
|
||
|
virtual bool ShouldHibernate();
|
||
|
|
||
|
// IGameEventListener2
|
||
|
virtual void FireGameEvent( IGameEvent *event ) OVERRIDE;
|
||
|
|
||
|
CTFParty* GetPartyForPlayer( CSteamID steamID ) const;
|
||
|
|
||
|
CMatchInfo *GetMatch() { return m_pMatchInfo; }
|
||
|
const CMatchInfo *GetMatch() const { return m_pMatchInfo; }
|
||
|
|
||
|
// Verbose accessor helpers
|
||
|
//
|
||
|
// Get match only if it is live
|
||
|
CMatchInfo *GetLiveMatch() { return ( m_pMatchInfo && !m_pMatchInfo->m_bMatchEnded ) ? m_pMatchInfo : NULL; }
|
||
|
const CMatchInfo *GetLiveMatch() const { return const_cast<CTFGCServerSystem*>(this)->GetLiveMatch(); }
|
||
|
// Get a player only if there is a live match and they are still in the match (not dropped)
|
||
|
CMatchInfo::PlayerMatchData_t *GetLiveMatchPlayer( CSteamID steamID );
|
||
|
const CMatchInfo::PlayerMatchData_t *GetLiveMatchPlayer( CSteamID steamID ) const ;
|
||
|
|
||
|
int GetTeamForLobbyMember( const CSteamID &steamId ) const;
|
||
|
// bool IsLobbyMemberBroadcaster( const CSteamID &steamId ) const;
|
||
|
// ELanguage GetBroadcasterLanguage( const CSteamID &steamId ) const;
|
||
|
float GetFirstConnectTimeForLobbyMember( const CSteamID &steamId ) const;
|
||
|
int GetVoteKickAttemptsByLobbyMember( const CSteamID &steamID ) const;
|
||
|
void IncrementVoteKickAttemptsByLobbyMember( const CSteamID &steamID );
|
||
|
//
|
||
|
// EDOTA_Uploading_Match_Stats UploadingMatchStats() { return m_nUploadingMatchStats; }
|
||
|
// void OnStatsSubmitted( uint32 unMatchID, int32 nReplaySalt );
|
||
|
// uint32 GetLastMatchID() { return m_unLastMatchID; }
|
||
|
// int32 GetLastReplaySalt() { return m_nLastReplaySalt; }
|
||
|
|
||
|
void ClientActive( CSteamID steamIDClient );
|
||
|
void ClientConnected( CSteamID steamIDPlayer, edict_t *pEntity );
|
||
|
void ClientDisconnected( CSteamID steamIDClient );
|
||
|
|
||
|
inline bool IsMMServerModeActive() const { return m_bMMServerMode; }
|
||
|
|
||
|
void MMServerModeChanged();
|
||
|
|
||
|
// void SetRelayedGameServerSteamID( const CSteamID &steamID ) { m_relayedGameServerSteamID = steamID; }
|
||
|
// void SetParentRelayCount( int nParentRelayCount ) { m_nParentRelayCount = nParentRelayCount; }
|
||
|
|
||
|
float GetTimeLastConnectedToGC( void ) { return m_timeLastConnectedToGC; }
|
||
|
|
||
|
void EndManagedMatch( bool bKickPlayersToParties = false );
|
||
|
|
||
|
// Sends match results. Expects the managed match be ended.
|
||
|
|
||
|
/// MvM game rules processing lets us the players have won
|
||
|
void SendMvMVictoryResult();
|
||
|
|
||
|
// Takes ownership of matchResultMsg
|
||
|
void SendCompetitiveMatchResult( GCSDK::CProtoBufMsg< CMsgGC_Match_Result > *matchResultMsg );
|
||
|
|
||
|
// If the GC has confirmed we are in the pool for late joins. GetTimeRequestedLateJoin() can be compared with
|
||
|
// BLateJoinEligible() to reason about delays in the GC making us available for late join.
|
||
|
bool BLateJoinEligible();
|
||
|
|
||
|
double GetTimeRequestedLateJoin() { return m_flTimeRequestedLateJoin; }
|
||
|
|
||
|
// Eject a player from the match, kicking them if they are still present, with given reason.
|
||
|
bool EjectMatchPlayer( CSteamID steamID, TFMatchLeaveReason eReason );
|
||
|
|
||
|
void MatchPlayerVoteKicked( CSteamID steamID );
|
||
|
|
||
|
const MapDef_t* GetNextMapVoteByIndex( int nIndex ) const;
|
||
|
|
||
|
// Changing Match Player Teams
|
||
|
//
|
||
|
// Is game logic allowed to perform team reassignments for this match mode?
|
||
|
bool CanChangeMatchPlayerTeams();
|
||
|
// When game logic changes the team of a match player, this should be called immediately. It is invalid to call this
|
||
|
// if CanChangeMatchPlayerTeams is false.
|
||
|
void ChangeMatchPlayerTeam( CSteamID steamID, TF_GC_TEAM eTeam );
|
||
|
// Multi-player version of the above, less GC traffic when multiple reassignments occur at once.
|
||
|
struct PlayerTeamPair_t { CSteamID steamID; TF_GC_TEAM eTeam; };
|
||
|
template< typename ANY_ALLOCATOR >
|
||
|
void ChangeMatchPlayerTeams( const CUtlVector< PlayerTeamPair_t, ANY_ALLOCATOR > &vecNewTeams );
|
||
|
|
||
|
// Rolling Matches
|
||
|
//
|
||
|
// Some match types let us keep a lobby and roll into a new match. This may not always be allowed depending on GC
|
||
|
// state.
|
||
|
//
|
||
|
// Upon calling RequestNewMatchForLobby, a timer starts, after which the new match is launched in
|
||
|
// LaunchNewMatchForLobby. During this period our match object is the old match, but the lobby may have been updated
|
||
|
// to reflect the new match.
|
||
|
//
|
||
|
// !! Currently if the GC is out of contact, we will speculatively continue with a new match. There are rare cases
|
||
|
// where the GC will return and decline this request, in which case the resulting match will be unofficial and
|
||
|
// not recorded. It should be trivial to add a bool to prevent such speculative matches should it be necessary.
|
||
|
bool CanRequestNewMatchForLobby();
|
||
|
void RequestNewMatchForLobby( const MapDef_t* pNewMap );
|
||
|
|
||
|
// If the match is in a bogus state and has no useful resolution, terminate it and submit a minidump. This usually
|
||
|
// just means reboot the match server.
|
||
|
void AbortInvalidMatchState();
|
||
|
|
||
|
protected:
|
||
|
|
||
|
// CGCClientSystem
|
||
|
virtual void PreInitGC() OVERRIDE;
|
||
|
virtual void PostInitGC() OVERRIDE;
|
||
|
|
||
|
private:
|
||
|
void SendPlayerLeftMatch( CSteamID steamID, TFMatchLeaveReason eReason, bool bAbandoned );
|
||
|
|
||
|
// Send a kick-lobby message for a stale or unexpected lobby
|
||
|
void SendRejectLobby();
|
||
|
|
||
|
// Kick a player that is no longer present in the match and should not be here.
|
||
|
// Returns true if they were present
|
||
|
bool KickRemovedMatchPlayer( CSteamID steamIDClient );
|
||
|
|
||
|
// The lobby object should only be looked at by this class and may be out of date when the GC reboots and similar --
|
||
|
// most users should use the canonical match state in GetMatch()
|
||
|
const CTFGSLobby *GetLobby() const;
|
||
|
CTFGSLobby *GetLobby();
|
||
|
|
||
|
// Accepts a reservation request from the GC, adding this player to our reserved list, and, for MM mode, to the
|
||
|
// match.
|
||
|
void AcceptGCReservation( CSteamID steamID, const CTFLobbyMember *pMemberData, bool bIsLateJoin, int nEntindex, bool bActive );
|
||
|
|
||
|
// Rolling Matches (private)
|
||
|
//
|
||
|
// If we requested a new match for our existing lobby. We don't actually launch the new match for this timer, but
|
||
|
// the GC may get back to us before (or after!) that period, so this tracks that we're not currently in sync with
|
||
|
// our lobby object. See RequestNewMatchForLobby / LaunchNewMatchForLobby and the "Team Assignments" section of the
|
||
|
// big comment at the top of tf_gc_server.cpp
|
||
|
bool BPendingNewMatch() const { return m_flWaitingForNewMatchTime != 0.f; }
|
||
|
// Called at the end of the m_flWaitingForNewMatchTime period to actually create the new match. We could let the
|
||
|
// caller finish the launch process by changing this timer to a bool and making this public.
|
||
|
void LaunchNewMatchForLobby();
|
||
|
|
||
|
// Callbacks from the GC
|
||
|
void ChangeMatchPlayerTeamsResponse( bool bSuccess );
|
||
|
void NewMatchForLobbyResponse( bool bSuccess );
|
||
|
// Static callbacks that are just forwarding to us
|
||
|
static void ChangeMatchPlayerTeamsResponseCallback( GCSDK::CProtoBufMsg<CMsgGCChangeMatchPlayerTeamsResponse>& msg );
|
||
|
static void NewMatchForLobbyResponseCallback( GCSDK::CProtoBufMsg<CMsgGCNewMatchForLobbyResponse>& msg );
|
||
|
|
||
|
bool m_bSetupSchema;
|
||
|
|
||
|
RTime32 m_unGameStartTime;
|
||
|
float m_timeLastSendGameServerInfoAndConnectedPlayers;
|
||
|
ServerMatchmakingState m_eLastGameServerUpdateState;
|
||
|
TF_MatchmakingMode m_eLastGameServerUpdateMatchmakingMode;
|
||
|
CUtlString m_sLastGameServerUpdateMap;
|
||
|
CUtlString m_sLastGameServerUpdateTags;
|
||
|
int m_nLastGameServerUpdateBotCount;
|
||
|
int m_nLastGameServerUpdateMaxHumans;
|
||
|
int m_nLastGameServerUpdateSlotsFree;
|
||
|
uint32 m_nLastGameServerUpdateLobbyMMVersion;
|
||
|
|
||
|
// EDOTA_Uploading_Match_Stats m_nUploadingMatchStats;
|
||
|
// uint32 m_unLastMatchID;
|
||
|
// int32 m_nLastReplaySalt;
|
||
|
CSteamID m_ourSteamID;
|
||
|
CSteamID m_relayedGameServerSteamID;
|
||
|
int m_nParentRelayCount;
|
||
|
bool m_bMMServerMode;
|
||
|
double m_flTimeBecameEmptyWithLobby;
|
||
|
double m_flTimeRequestedLateJoin;
|
||
|
bool m_bLateJoinEligible;
|
||
|
int m_iSavedVisibleMaxPlayers;
|
||
|
bool m_bOverridingVisibleMaxPlayers;
|
||
|
bool m_bWaitingForNewMatchID;
|
||
|
float m_flWaitingForNewMatchTime;
|
||
|
|
||
|
CMvMVictoryInfo m_mvmVictoryInfo;
|
||
|
|
||
|
// Check for match players who have been disconnected for long enough to warrant an abandon and do so.
|
||
|
void MatchPlayerAbandonThink();
|
||
|
|
||
|
void SetMatchPlayerDropped( CSteamID steamID, TFMatchLeaveReason eReason );
|
||
|
|
||
|
void UpdateConnectedPlayersAndServerInfo( CMsgGameServerMatchmakingStatus_Event event, bool bForceSendServerInfo );
|
||
|
|
||
|
CMatchInfo *m_pMatchInfo;
|
||
|
float m_timeLastConnectedToGC;
|
||
|
|
||
|
// DOTAGameVersion m_GameVersion;
|
||
|
};
|
||
|
|
||
|
CTFGCServerSystem *GTFGCClientSystem();
|
||
|
|
||
|
#endif // #ifdef ENABLE_GC_MATCHMAKING
|
||
|
|
||
|
#endif // TF_GC_SERVER_H
|