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.
539 lines
20 KiB
539 lines
20 KiB
//========= 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
|
|
|