about summary refs log tree commit diff
diff options
context:
space:
mode:
authoroy <Tom_Adams@web.de>2011-03-20 15:33:49 +0100
committeroy <Tom_Adams@web.de>2011-03-20 15:33:49 +0100
commit96808a11451f2ccf22346253bd22f8f559207ac8 (patch)
treea91ecb0ea18cff36e8515f234c5028c6c1c1b628
parent2547bfa4fcc8916a47eceb9a929fe73c8a1d83b9 (diff)
downloadzcatch-96808a11451f2ccf22346253bd22f8f559207ac8.tar.gz
zcatch-96808a11451f2ccf22346253bd22f8f559207ac8.zip
made it possible to just show the number of player slots of a server (instead of client ones). Closes #68
-rw-r--r--src/engine/client/client.cpp26
-rw-r--r--src/engine/client/srvbrowse.cpp19
-rw-r--r--src/engine/client/srvbrowse.h1
-rw-r--r--src/engine/server.h1
-rw-r--r--src/engine/server/server.cpp23
-rw-r--r--src/engine/serverbrowser.h9
-rw-r--r--src/engine/shared/config_variables.h1
-rw-r--r--src/game/client/components/menus_browser.cpp30
-rw-r--r--src/game/client/components/menus_ingame.cpp2
-rw-r--r--src/game/server/gamecontext.cpp5
-rw-r--r--src/game/server/gamecontext.h1
11 files changed, 82 insertions, 36 deletions
diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp
index 723b8791..cb477304 100644
--- a/src/engine/client/client.cpp
+++ b/src/engine/client/client.cpp
@@ -1018,8 +1018,12 @@ const char *CClient::LoadMapSearch(const char *pMapName, int WantedCrc)
 
 int CClient::PlayerScoreComp(const void *a, const void *b)
 {
-	CServerInfo::CPlayer *p0 = (CServerInfo::CPlayer *)a;
-	CServerInfo::CPlayer *p1 = (CServerInfo::CPlayer *)b;
+	CServerInfo::CClient *p0 = (CServerInfo::CClient *)a;
+	CServerInfo::CClient *p1 = (CServerInfo::CClient *)b;
+	if(p0->m_Player && !p1->m_Player)
+		return -1;
+	if(!p0->m_Player && p1->m_Player)
+		return 1;
 	if(p0->m_Score == p1->m_Score)
 		return 0;
 	if(p0->m_Score < p1->m_Score)
@@ -1106,27 +1110,31 @@ void CClient::ProcessConnlessPacket(CNetChunk *pPacket)
 		Info.m_Flags = str_toint(Up.GetString());
 		Info.m_NumPlayers = str_toint(Up.GetString());
 		Info.m_MaxPlayers = str_toint(Up.GetString());
+		Info.m_NumClients = str_toint(Up.GetString());
+		Info.m_MaxClients = str_toint(Up.GetString());
 
 		// don't add invalid info to the server browser list
-		if(Info.m_NumPlayers < 0 || Info.m_NumPlayers > MAX_CLIENTS || Info.m_MaxPlayers < 0 || Info.m_MaxPlayers > MAX_CLIENTS)
+		if(Info.m_NumClients < 0 || Info.m_NumClients > MAX_CLIENTS || Info.m_MaxClients < 0 || Info.m_MaxClients > MAX_CLIENTS ||
+			Info.m_NumPlayers < 0 || Info.m_NumPlayers > Info.m_NumClients || Info.m_MaxPlayers < 0 || Info.m_MaxPlayers > Info.m_MaxClients)
 			return;
 
 		str_format(Info.m_aAddress, sizeof(Info.m_aAddress), "%d.%d.%d.%d:%d",
 			pPacket->m_Address.ip[0], pPacket->m_Address.ip[1], pPacket->m_Address.ip[2],
 			pPacket->m_Address.ip[3], pPacket->m_Address.port);
 
-		for(int i = 0; i < Info.m_NumPlayers; i++)
+		for(int i = 0; i < Info.m_NumClients; i++)
 		{
-			str_copy(Info.m_aPlayers[i].m_aName, Up.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(Info.m_aPlayers[i].m_aName));
-			str_copy(Info.m_aPlayers[i].m_aClan, Up.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(Info.m_aPlayers[i].m_aClan));
-			Info.m_aPlayers[i].m_Country = GameClient()->GetCountryIndex(str_toint(Up.GetString()));
-			Info.m_aPlayers[i].m_Score = str_toint(Up.GetString());
+			str_copy(Info.m_aClients[i].m_aName, Up.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(Info.m_aClients[i].m_aName));
+			str_copy(Info.m_aClients[i].m_aClan, Up.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(Info.m_aClients[i].m_aClan));
+			Info.m_aClients[i].m_Country = GameClient()->GetCountryIndex(str_toint(Up.GetString()));
+			Info.m_aClients[i].m_Score = str_toint(Up.GetString());
+			Info.m_aClients[i].m_Player = str_toint(Up.GetString()) != 0 ? true : false;
 		}
 
 		if(!Up.Error())
 		{
 			// sort players
-			qsort(Info.m_aPlayers, Info.m_NumPlayers, sizeof(*Info.m_aPlayers), PlayerScoreComp);
+			qsort(Info.m_aClients, Info.m_NumClients, sizeof(*Info.m_aClients), PlayerScoreComp);
 
 			if(net_addr_comp(&m_ServerAddress, &pPacket->m_Address) == 0)
 			{
diff --git a/src/engine/client/srvbrowse.cpp b/src/engine/client/srvbrowse.cpp
index fb350c43..506d2e02 100644
--- a/src/engine/client/srvbrowse.cpp
+++ b/src/engine/client/srvbrowse.cpp
@@ -115,6 +115,13 @@ bool CServerBrowser::SortCompareNumPlayers(int Index1, int Index2) const
 	return a->m_Info.m_NumPlayers < b->m_Info.m_NumPlayers;
 }
 
+bool CServerBrowser::SortCompareNumClients(int Index1, int Index2) const
+{
+	CServerEntry *a = m_ppServerlist[Index1];
+	CServerEntry *b = m_ppServerlist[Index2];
+	return a->m_Info.m_NumClients < b->m_Info.m_NumClients;
+}
+
 void CServerBrowser::Filter()
 {
 	int i = 0, p = 0;
@@ -134,9 +141,10 @@ void CServerBrowser::Filter()
 	{
 		int Filtered = 0;
 
-		if(g_Config.m_BrFilterEmpty && m_ppServerlist[i]->m_Info.m_NumPlayers == 0)
+		if(g_Config.m_BrFilterEmpty && ((g_Config.m_BrFilterSpectators && m_ppServerlist[i]->m_Info.m_NumPlayers == 0) || m_ppServerlist[i]->m_Info.m_NumClients == 0))
 			Filtered = 1;
-		else if(g_Config.m_BrFilterFull && m_ppServerlist[i]->m_Info.m_NumPlayers == m_ppServerlist[i]->m_Info.m_MaxPlayers)
+		else if(g_Config.m_BrFilterFull && ((g_Config.m_BrFilterSpectators && m_ppServerlist[i]->m_Info.m_NumPlayers == m_ppServerlist[i]->m_Info.m_MaxPlayers) ||
+				m_ppServerlist[i]->m_Info.m_NumClients == m_ppServerlist[i]->m_Info.m_MaxClients))
 			Filtered = 1;
 		else if(g_Config.m_BrFilterPw && m_ppServerlist[i]->m_Info.m_Flags&SERVER_FLAG_PASSWORD)
 			Filtered = 1;
@@ -187,8 +195,8 @@ void CServerBrowser::Filter()
 			// match against players
 			for(p = 0; p < m_ppServerlist[i]->m_Info.m_NumPlayers; p++)
 			{
-				if(str_find_nocase(m_ppServerlist[i]->m_Info.m_aPlayers[p].m_aName, g_Config.m_BrFilterString) ||
-					str_find_nocase(m_ppServerlist[i]->m_Info.m_aPlayers[p].m_aClan, g_Config.m_BrFilterString))
+				if(str_find_nocase(m_ppServerlist[i]->m_Info.m_aClients[p].m_aName, g_Config.m_BrFilterString) ||
+					str_find_nocase(m_ppServerlist[i]->m_Info.m_aClients[p].m_aClan, g_Config.m_BrFilterString))
 				{
 					MatchFound = 1;
 					m_ppServerlist[i]->m_Info.m_QuickSearchHit |= IServerBrowser::QUICK_PLAYER;
@@ -241,7 +249,8 @@ void CServerBrowser::Sort()
 	else if(g_Config.m_BrSort == IServerBrowser::SORT_MAP)
 		std::sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, &CServerBrowser::SortCompareMap));
 	else if(g_Config.m_BrSort == IServerBrowser::SORT_NUMPLAYERS)
-		std::sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, &CServerBrowser::SortCompareNumPlayers));
+		std::sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this,
+					g_Config.m_BrFilterSpectators ? &CServerBrowser::SortCompareNumPlayers : &CServerBrowser::SortCompareNumClients));
 	else if(g_Config.m_BrSort == IServerBrowser::SORT_GAMETYPE)
 		std::sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, &CServerBrowser::SortCompareGametype));
 
diff --git a/src/engine/client/srvbrowse.h b/src/engine/client/srvbrowse.h
index c00ce752..b3d0f9ed 100644
--- a/src/engine/client/srvbrowse.h
+++ b/src/engine/client/srvbrowse.h
@@ -93,6 +93,7 @@ private:
 	bool SortComparePing(int Index1, int Index2) const;
 	bool SortCompareGametype(int Index1, int Index2) const;
 	bool SortCompareNumPlayers(int Index1, int Index2) const;
+	bool SortCompareNumClients(int Index1, int Index2) const;
 
 	//
 	void Filter();
diff --git a/src/engine/server.h b/src/engine/server.h
index edc60767..7e11d865 100644
--- a/src/engine/server.h
+++ b/src/engine/server.h
@@ -82,6 +82,7 @@ public:
 	virtual void OnClientPredictedInput(int ClientID, void *pInput) = 0;
 
 	virtual bool IsClientReady(int ClientID) = 0;
+	virtual bool IsClientPlayer(int ClientID) = 0;
 	
 	virtual const char *GameType() = 0;
 	virtual const char *Version() = 0;
diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp
index e2408a10..c3ba583b 100644
--- a/src/engine/server/server.cpp
+++ b/src/engine/server/server.cpp
@@ -911,11 +911,16 @@ void CServer::SendServerInfo(NETADDR *pAddr, int Token)
 	char aBuf[128];
 
 	// count the players
-	int PlayerCount = 0;
+	int PlayerCount = 0, ClientCount = 0;
 	for(int i = 0; i < MAX_CLIENTS; i++)
 	{
 		if(m_aClients[i].m_State != CClient::STATE_EMPTY)
-			PlayerCount++;
+		{
+			if(GameServer()->IsClientPlayer(i))
+				PlayerCount++;
+			
+			ClientCount++;
+		}
 	}
 	
 	p.Reset();
@@ -939,20 +944,22 @@ void CServer::SendServerInfo(NETADDR *pAddr, int Token)
 	p.AddString(aBuf, 2);
 
 	str_format(aBuf, sizeof(aBuf), "%d", PlayerCount); p.AddString(aBuf, 3);  // num players
-	str_format(aBuf, sizeof(aBuf), "%d", m_NetServer.MaxClients()); p.AddString(aBuf, 3); // max players
+	str_format(aBuf, sizeof(aBuf), "%d", m_NetServer.MaxClients()-g_Config.m_SvSpectatorSlots); p.AddString(aBuf, 3); // max players
+	str_format(aBuf, sizeof(aBuf), "%d", ClientCount); p.AddString(aBuf, 3);  // num clients
+	str_format(aBuf, sizeof(aBuf), "%d", m_NetServer.MaxClients()); p.AddString(aBuf, 3); // max clients
 
 	for(i = 0; i < MAX_CLIENTS; i++)
 	{
 		if(m_aClients[i].m_State != CClient::STATE_EMPTY)
 		{
-			p.AddString(ClientName(i), MAX_NAME_LENGTH);  // player name
-			p.AddString(ClientClan(i), MAX_CLAN_LENGTH);  // player clan
-			str_format(aBuf, sizeof(aBuf), "%d", m_aClients[i].m_Country); p.AddString(aBuf, 6);  // player country
-			str_format(aBuf, sizeof(aBuf), "%d", m_aClients[i].m_Score); p.AddString(aBuf, 6);  // player score
+			p.AddString(ClientName(i), MAX_NAME_LENGTH);  // client name
+			p.AddString(ClientClan(i), MAX_CLAN_LENGTH);  // client clan
+			str_format(aBuf, sizeof(aBuf), "%d", m_aClients[i].m_Country); p.AddString(aBuf, 6);  // client country
+			str_format(aBuf, sizeof(aBuf), "%d", m_aClients[i].m_Score); p.AddString(aBuf, 6);  // client score
+			str_format(aBuf, sizeof(aBuf), "%d", GameServer()->IsClientPlayer(i)?1:0); p.AddString(aBuf, 2);  // is player?
 		}
 	}
 	
-	
 	Packet.m_ClientID = -1;
 	Packet.m_Address = *pAddr;
 	Packet.m_Flags = NETSENDFLAG_CONNLESS;
diff --git a/src/engine/serverbrowser.h b/src/engine/serverbrowser.h
index 579f1ca7..f0310421 100644
--- a/src/engine/serverbrowser.h
+++ b/src/engine/serverbrowser.h
@@ -14,15 +14,16 @@ class CServerInfo
 {
 public:
 	/*
-		Structure: CInfoPlayer
+		Structure: CInfoClient
 	*/
-	class CPlayer
+	class CClient
 	{
 	public:
 		char m_aName[MAX_NAME_LENGTH];
 		char m_aClan[MAX_CLAN_LENGTH];
 		int m_Country;
 		int m_Score;
+		bool m_Player;
 	} ;
 
 	int m_SortedIndex;
@@ -32,6 +33,8 @@ public:
 	
 	int m_QuickSearchHit;
 	
+	int m_MaxClients;
+	int m_NumClients;
 	int m_MaxPlayers;
 	int m_NumPlayers;
 	int m_Flags;
@@ -42,7 +45,7 @@ public:
 	char m_aMap[32];
 	char m_aVersion[32];
 	char m_aAddress[24];
-	CPlayer m_aPlayers[MAX_CLIENTS];
+	CClient m_aClients[MAX_CLIENTS];
 };
 
 class IServerBrowser : public IInterface
diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h
index 68e615bd..b95839ba 100644
--- a/src/engine/shared/config_variables.h
+++ b/src/engine/shared/config_variables.h
@@ -30,6 +30,7 @@ MACRO_CONFIG_INT(InpGrab, inp_grab, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Use f
 MACRO_CONFIG_STR(BrFilterString, br_filter_string, 25, "", CFGFLAG_SAVE|CFGFLAG_CLIENT, "Server browser filtering string")
 MACRO_CONFIG_INT(BrFilterFull, br_filter_full, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Filter out full server in browser")
 MACRO_CONFIG_INT(BrFilterEmpty, br_filter_empty, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Filter out empty server in browser")
+MACRO_CONFIG_INT(BrFilterSpectators, br_filter_spectators, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Filter out spectators from player numbers")
 MACRO_CONFIG_INT(BrFilterPw, br_filter_pw, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Filter out password protected servers in browser")
 MACRO_CONFIG_INT(BrFilterPing, br_filter_ping, 999, 0, 999, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Ping to filter by in the server browser")
 MACRO_CONFIG_STR(BrFilterGametype, br_filter_gametype, 128, "", CFGFLAG_SAVE|CFGFLAG_CLIENT, "Game types to filter")
diff --git a/src/game/client/components/menus_browser.cpp b/src/game/client/components/menus_browser.cpp
index 8f2b2500..952d596d 100644
--- a/src/game/client/components/menus_browser.cpp
+++ b/src/game/client/components/menus_browser.cpp
@@ -351,7 +351,10 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
 			}
 			else if(ID == COL_PLAYERS)
 			{
-				str_format(aTemp, sizeof(aTemp), "%i/%i", pItem->m_NumPlayers, pItem->m_MaxPlayers);
+				if(g_Config.m_BrFilterSpectators)
+					str_format(aTemp, sizeof(aTemp), "%i/%i", pItem->m_NumPlayers, pItem->m_MaxPlayers);
+				else
+					str_format(aTemp, sizeof(aTemp), "%i/%i", pItem->m_NumClients, pItem->m_MaxClients);
 				if(g_Config.m_BrFilterString[0] && (pItem->m_QuickSearchHit&IServerBrowser::QUICK_PLAYER))
 					TextRender()->TextColor(0.4f,0.4f,1.0f,1);
 				UI()->DoLabelScaled(&Button, aTemp, 12.0f, 1);
@@ -450,6 +453,10 @@ void CMenus::RenderServerbrowserFilters(CUIRect View)
 		g_Config.m_BrFilterEmpty ^= 1;
 
 	ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter);
+	if(DoButton_CheckBox(&g_Config.m_BrFilterSpectators, Localize("Count players only"), g_Config.m_BrFilterSpectators, &Button))
+		g_Config.m_BrFilterSpectators ^= 1;
+
+	ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter);
 	if (DoButton_CheckBox(&g_Config.m_BrFilterFull, Localize("Server not full"), g_Config.m_BrFilterFull, &Button))
 		g_Config.m_BrFilterFull ^= 1;
 
@@ -608,7 +615,7 @@ void CMenus::RenderServerbrowserServerDetail(CUIRect View)
 	{
 		ServerScoreBoard.VSplitLeft(5.0f, 0, &ServerScoreBoard);
 		ServerScoreBoard.Margin(3.0f, &ServerScoreBoard);
-		for (int i = 0; i < pSelectedServer->m_NumPlayers; i++)
+		for (int i = 0; i < pSelectedServer->m_NumClients; i++)
 		{
 			CUIRect Name, Clan, Score, Flag;
 			ServerScoreBoard.HSplitTop(25.0f, &Name, &ServerScoreBoard);
@@ -618,16 +625,19 @@ void CMenus::RenderServerbrowserServerDetail(CUIRect View)
 			Name.HSplitTop(12.0f, &Name, &Clan);
 
 			// score
-			char aTemp[16];
-			str_format(aTemp, sizeof(aTemp), "%d", pSelectedServer->m_aPlayers[i].m_Score);
-			TextRender()->SetCursor(&Cursor, Score.x, Score.y+(Score.h-FontSize)/2.0f, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
-			Cursor.m_LineWidth = Score.w;
-			TextRender()->TextEx(&Cursor, aTemp, -1);
+			if(pSelectedServer->m_aClients[i].m_Player)
+			{
+				char aTemp[16];
+				str_format(aTemp, sizeof(aTemp), "%d", pSelectedServer->m_aClients[i].m_Score);
+				TextRender()->SetCursor(&Cursor, Score.x, Score.y+(Score.h-FontSize)/2.0f, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
+				Cursor.m_LineWidth = Score.w;
+				TextRender()->TextEx(&Cursor, aTemp, -1);
+			}
 	
 			// name
 			TextRender()->SetCursor(&Cursor, Name.x, Name.y, FontSize-2, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
 			Cursor.m_LineWidth = Name.w;
-			const char *pName = pSelectedServer->m_aPlayers[i].m_aName;
+			const char *pName = pSelectedServer->m_aClients[i].m_aName;
 			if(g_Config.m_BrFilterString[0])
 			{
 				// highlight the parts that matches
@@ -649,7 +659,7 @@ void CMenus::RenderServerbrowserServerDetail(CUIRect View)
 			// clan
 			TextRender()->SetCursor(&Cursor, Clan.x, Clan.y, FontSize-2, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
 			Cursor.m_LineWidth = Clan.w;
-			const char *pClan = pSelectedServer->m_aPlayers[i].m_aClan;
+			const char *pClan = pSelectedServer->m_aClients[i].m_aClan;
 			if(g_Config.m_BrFilterString[0])
 			{
 				// highlight the parts that matches
@@ -669,7 +679,7 @@ void CMenus::RenderServerbrowserServerDetail(CUIRect View)
 				TextRender()->TextEx(&Cursor, pClan, -1);
 
 			// flag
-			Graphics()->TextureSet(m_pClient->m_pCountryFlags->Get(pSelectedServer->m_aPlayers[i].m_Country)->m_Texture);
+			Graphics()->TextureSet(m_pClient->m_pCountryFlags->Get(pSelectedServer->m_aClients[i].m_Country)->m_Texture);
 			Graphics()->QuadsBegin();
 			Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
 			IGraphics::CQuadItem QuadItem(Flag.x, Flag.y, Flag.w, Flag.h);
diff --git a/src/game/client/components/menus_ingame.cpp b/src/game/client/components/menus_ingame.cpp
index d49c96e2..ef3d0236 100644
--- a/src/game/client/components/menus_ingame.cpp
+++ b/src/game/client/components/menus_ingame.cpp
@@ -252,7 +252,7 @@ void CMenus::RenderServerInfo(CUIRect MainView)
 			Localize("Map"), CurrentServerInfo.m_aMap,
 			Localize("Score limit"), m_pClient->m_Snap.m_pGameInfoObj->m_ScoreLimit,
 			Localize("Time limit"), m_pClient->m_Snap.m_pGameInfoObj->m_TimeLimit,
-			Localize("Players"), m_pClient->m_Snap.m_NumPlayers, CurrentServerInfo.m_MaxPlayers
+			Localize("Players"), m_pClient->m_Snap.m_NumPlayers, CurrentServerInfo.m_MaxClients
 		);
 		TextRender()->Text(0, GameInfo.x+x, GameInfo.y+y, 20, aBuf, 250);
 	}
diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp
index 348b6735..1612ebec 100644
--- a/src/game/server/gamecontext.cpp
+++ b/src/game/server/gamecontext.cpp
@@ -1184,6 +1184,11 @@ bool CGameContext::IsClientReady(int ClientID)
 	return m_apPlayers[ClientID] && m_apPlayers[ClientID]->m_IsReady ? true : false;
 }
 
+bool CGameContext::IsClientPlayer(int ClientID)
+{
+	return m_apPlayers[ClientID] && m_apPlayers[ClientID]->GetTeam() == TEAM_SPECTATORS ? false : true;
+}
+
 const char *CGameContext::GameType() { return m_pController && m_pController->m_pGameType ? m_pController->m_pGameType : ""; }
 const char *CGameContext::Version() { return GAME_VERSION; }
 const char *CGameContext::NetVersion() { return GAME_NETVERSION; }
diff --git a/src/game/server/gamecontext.h b/src/game/server/gamecontext.h
index f64232a1..7379b74d 100644
--- a/src/game/server/gamecontext.h
+++ b/src/game/server/gamecontext.h
@@ -162,6 +162,7 @@ public:
 	virtual void OnClientPredictedInput(int ClientID, void *pInput);
 
 	virtual bool IsClientReady(int ClientID);
+	virtual bool IsClientPlayer(int ClientID);
 
 	virtual const char *GameType();
 	virtual const char *Version();